WPF 做一个超级简单的 1024 数字接龙游戏

wpf · 浏览次数 : 3

小编点评

本文介绍了一个简单的逻辑游戏,玩家需要在多个列表中选择一个数字放置。当选择与列表中最后一个数字相同时,数字会合并。游戏的目标是将所有数字合并至一个列表。 1. **游戏规则**:游戏包含多个列表,玩家选择一个数字放入任意一个列表。若该数字与列表中的最后一个数字相同,则合并这两个数字。 2. **用户界面**:界面包括一个数字列表,每个列表下方有一个点击按钮。点击按钮后,数字会被添加到相应的列表中,并尝试合并相邻的数字。 3. **代码实现**:文章提供了用户控件(CecaqemdarYefarqukeafai)的XAML和CS文件,以及主界面(MainWindow)的XAML文件。用户控件和主界面均实现了所需的功能。 4. **算法设计**:文章还提供了一个简单的算法,使游戏具有自动生成数字的能力。通过加载主界面,玩家可以体验到游戏的趣味性。 5. **GitHub链接**:文章最后提供了项目的GitHub和Gitee链接,供读者获取源代码并自行尝试。 总的来说,这是一个简单的逻辑游戏,通过简单的用户界面和代码实现,玩家可以在多个列表中选择一个数字放置。游戏的核心机制在于合并相邻的数字,最终目标是将所有数字合并至一个列表。

正文

这是一个我给自己做着玩的游戏,没有什么复杂的界面,就一些简单的逻辑

游戏的规则十分简单,那就是有多个列表。程序会给出一个数字,玩家决定数字放在哪个列表里面。如果放入列表里面的数字和列表里面最后一个数字相同,那两个数字将会叠加进行合并,合并两个 1024 将会自动清理掉整个列表

如下图,有 5 个列表。最右边有一个数字。此时点击列表下方的 "点击" 按钮,即表示将最右边的数字放在这一列表中

如下图,就是点击了首个列表的“点击”按钮,将上图的 1024 数字放在首个列表里

如下图,首个列表里面的最后一个是 2 的数字,最右边的数字也是 2 的数字,可以将其进行合并

如下图,合并之后,首个列表的 2 将会和最右边的数字 2 合并为 4 作为最后一个数字

规则介绍完了,接下来咱来开始开发咯。如果只是想玩这个简单的游戏的伙伴,可以快速到本文末尾,找到本文的所有代码的下载方法

如上面的界面图,可以看到有多个列表,那不如每个列表就一个 UserControl 用户控件好了。这里没有什么最佳实践,这么简单的应用,想怎么写就怎么写就好了

我这里都不想好好命名,直接就用 Whitman 工具随机一个名为 CecaqemdarYefarqukeafai 的控件名好了

在 CecaqemdarYefarqukeafai.xaml.cs 里面存放一个 ObservableCollection<int> 集合,用来表示界面上每个列表里面的数据,代码如下

    public ObservableCollection<int> Collection { get; } = new ObservableCollection<int>();

在 CecaqemdarYefarqukeafai.xaml 的界面写一个 ListView 进行绑定这个 Collection 属性,代码如下

        <ListView ItemsSource="{Binding ElementName=Root,Path=Collection}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding .}"></TextBlock>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

这里我写的绑定是 ElementName=Root 的方式,这是我的习惯使用方法。对于简单没有 MVVM 的模式下,可以将控件自身当成自己的绑定源,这样在控件后台代码编写的属性就可以很方便进行绑定

具体的实现方法就是将用户控件自身加上 x:Name="Root" 属性,加上之后的用户控件的代码大概如下

<UserControl x:Class="BawjadurbaWurahuwa.CecaqemdarYefarqukeafai"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:BawjadurbaWurahuwa"
             mc:Ignorable="d" 
             x:Name="Root"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        ... 忽略其他代码
        <ListView ItemsSource="{Binding ElementName=Root,Path=Collection}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding .}"></TextBlock>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        ... 忽略其他代码
    </Grid>
</UserControl>

如上图界面,可以看到每个列表下方都有一个点击按钮。那就继续修改 CecaqemdarYefarqukeafai.xaml 界面,加上一个按钮,代码如下

        <Button Margin="10,10,10,10" HorizontalAlignment="Center" Click="Button_OnClick">点击</Button>

加上按钮需要稍微修改一下布局,修改一下 Grid 加上两行,代码如下

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>

以上就配置了列表的地方有多少空间使用多少空间,配置下面一行给按钮使用,按钮需要多少空间再给多少空间

修改之后的 CecaqemdarYefarqukeafai.xaml 的全部代码如下

<UserControl x:Class="BawjadurbaWurahuwa.CecaqemdarYefarqukeafai"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:BawjadurbaWurahuwa"
             mc:Ignorable="d" 
             x:Name="Root"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <ListView ItemsSource="{Binding ElementName=Root,Path=Collection}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding .}"></TextBlock>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button Grid.Row="1" Margin="10,10,10,10" HorizontalAlignment="Center" Click="Button_OnClick">点击</Button>
    </Grid>
</UserControl>

可以看到实现非常简单,即使不使用用户控件也是可以的

这里的点击按钮需要将事件给到外面订阅,编辑后台 CecaqemdarYefarqukeafai.xaml.cs 代码,实现按钮点击逻辑,代码如下

    public event EventHandler<CecaqemdarYefarqukeafai>? Click;

    private void Button_OnClick(object sender, RoutedEventArgs e)
    {
        Click?.Invoke(this, this);
    }

如此即可在点击按钮的时候,触发 Click 事件给到外面订阅

修改之后的 CecaqemdarYefarqukeafai.xaml.cs 的全部代码如下

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BawjadurbaWurahuwa;

/// <summary>
/// CecaqemdarYefarqukeafai.xaml 的交互逻辑
/// </summary>
public partial class CecaqemdarYefarqukeafai : UserControl
{
    public CecaqemdarYefarqukeafai()
    {
        InitializeComponent();
    }

    public ObservableCollection<int> Collection { get; } = new ObservableCollection<int>();

    public event EventHandler<CecaqemdarYefarqukeafai>? Click;

    private void Button_OnClick(object sender, RoutedEventArgs e)
    {
        Click?.Invoke(this, this);
    }
}

回到主界面

主界面需要显示 5 列,那就直接写 5 个 CecaqemdarYefarqukeafai 控件好了。如果数量更多的话,那可以试试写一个 ListView 之类的控件

如上图,整个主界面可以分为 6 列,其中前面 5 列是 CecaqemdarYefarqukeafai 控件,最后一列是一个文本,用来说明下一个数字

实现的 MainWindow.xaml 代码如下

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <local:CecaqemdarYefarqukeafai Click="CecaqemdarYefarqukeafai_OnClick"/>
        <local:CecaqemdarYefarqukeafai Grid.Column="1" Click="CecaqemdarYefarqukeafai_OnClick"/>
        <local:CecaqemdarYefarqukeafai Grid.Column="2" Click="CecaqemdarYefarqukeafai_OnClick"/>
        <local:CecaqemdarYefarqukeafai Grid.Column="3" Click="CecaqemdarYefarqukeafai_OnClick"/>
        <local:CecaqemdarYefarqukeafai Grid.Column="4" Click="CecaqemdarYefarqukeafai_OnClick"/>

        <TextBlock x:Name="CurrentTextBlock" Grid.Column="5" HorizontalAlignment="Center"></TextBlock>
    </Grid>

也许有伙伴开始好奇了,为什么上面代码里面的 5 个 CecaqemdarYefarqukeafai 的 Click 事件都是相同的方法,那方法内是如何区分点击的是哪个列表的?答案是不需要区分,在 CecaqemdarYefarqukeafai 的定义事件的代码里面,就将列表控件自身给传递进入了,如下面代码

public partial class CecaqemdarYefarqukeafai : UserControl
{
    ... // 忽略其他代码

    public event EventHandler<CecaqemdarYefarqukeafai>? Click;

    ... // 忽略其他代码
}

于是在 MainWindow.xaml.cs 后台代码实现方法里面,就可以通过参数了解到当前点击按钮属于哪个用户控件了

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        ... // 忽略其他代码
    }

为了方便拿到和表示当前最右侧显示的当前的数字,咱使用的是建立一个数组和一个索引的方式表示。如此即可实现后续进行随机给一个数字的方法,也可以让给出的数字一定在数组内。定义在 MainWindow.xaml.cs 的字段代码如下

    private int _index;

    private readonly int[] _list = new int[] { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2 };

那是否可以省略这个数组,没错,因为这些都是 2 的倍数,想要省略也是可以的。省略了这个数组,那就每次自己计算就好了。可不要觉得每次都重新计算速度很慢,对于现代 CPU 来说,你接近测试不出来这两者的性能差异。但总之这个数组也很小,占用内存基本可以忽略,就随大家想用什么就用什么咯

为什么有时候数组很小我也会关注,有时候数组即使不小我也不会关注。这其实和业务有关系,在本文例子里面的这个数组只有一次定义,且全局只有一个,那这个数组就这点空间,自然就可以忽略其占用内存了。但如果这个数组是需要每次都创建的,那这时候我可能会稍微考虑一下。如果这个数组是每次都需要创建的,且创建之后很难释放,那才会考虑一下

回到点击事件里面,通过索引和数组即可拿到当前最右侧的数字,代码如下

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        var number = _list[_index];

        ... // 忽略其他代码
    }

将此数字加入到 CecaqemdarYefarqukeafai 的集合里面,代码如下

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        var number = _list[_index];

        e.Collection.Add(number);

        ... // 忽略其他代码
    }

如此就完成了点击按钮就将数字加到所点击的一列的基础逻辑了

根据游戏规则,如果列表里面最后相邻的两个数字是相同的,则进行合并。接下来再写一个方法,这个方法用于合并集合的数字,代码如下

    private static void Clean(ObservableCollection<int> collection)
    {
        while (collection.Count > 1)
        {
            var n1 = collection[^1];
            var n2 = collection[^2];

            if (n1 == n2)
            {
                collection.RemoveAt(collection.Count - 1);
                collection.RemoveAt(collection.Count - 1);
                collection.Add(n1 + n2);
            }
            else
            {
                break;
            }
        }

        if (collection[^1] == 1024 * 2)
        {
            collection.Clear();
        }
    }

为了这个方法需要一个循环?这是因为如果最后的数字刚好是 4、2、2 的话,那就可以先对 2 和 2 进行合并,合并完成拿到的 4 再和 4 进行合并

合并的方法就是移除这两个数字,再添加一个新的更大的数字

为什么移除的时候都是使用 collection.RemoveAt(collection.Count - 1); 代码移除,为什么两次移除都是相同的代码?这是因为首先集合列表数组都是从 0 开始的,想象一下,一个只有元素的集合,想要移除最后一个元素,那下标是多少,没错就是 0 作为下标。因此 collection.Count - 1 表示的是最后一个元素。那为什么调用两次?这是因为第一次调用的时候,最后一个元素就被移除了。那原本倒数的第二个元素现在就成为倒数第一个元素了,自然再次移除最后一个元素就是移除掉原先的倒数第二个元素。举个例子,假如你每次都是全班倒数第二,某天全班倒数第一退学了,那你是不是就成为全班倒数第一了

如何全部合并之后,最后一个数字是两倍的 1024 则将列表清空。嗯,这里的话,只去掉当前这个数也可以,这个看大家的规则

完成了 Clean 方法之后,尝试调用一下,代码如下

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        var number = _list[_index];

        e.Collection.Add(number);

        Clean(e.Collection);

        ... // 忽略其他代码
    }

如此就完成了将数字加入到所点击的列表里面,且如果数字和列表最后一个数字相同则进行合并

根据游戏的规则,此时咱就需要再生成最右侧的新的数字了。如上文可以知道,最右侧的数字是使用数组和索引表示的,那就是随机生成一个在数组范围内的索引就可以了。既可以降低难度,按照顺序生成索引,如下面代码

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        ... // 忽略其他代码

        _index++;
        if (_index == _list.Length)
        {
            _index = 0;
        }

        ... // 忽略其他代码
    }

也可以使用随机数生成,代码如下

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        ... // 忽略其他代码

        _index = Random.Shared.Next(_list.Length);

        ... // 忽略其他代码
    }

生成完成之后,将结果设置到界面的 CurrentTextBlock 控件里面,如此即可在界面显示

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        ... // 忽略其他代码
        CurrentTextBlock.Text = $"第 {_count} 次\r\n下一个 {_list[_index]}";
    }

上述的 _count 字段这时一个类似游戏分数的作用,表示的是当前是第多少次,实现代码如下

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        _count++;
        ... // 忽略其他代码
        CurrentTextBlock.Text = $"第 {_count} 次\r\n下一个 {_list[_index]}";
    }

    private int _count;

最后别忘了修改一下 MainWindow 构造函数,在其初始化时给最右侧一个数字,代码如下

    public MainWindow()
    {
        InitializeComponent();
        CurrentTextBlock.Text = _list[_index].ToString();
    }

如此即可完成简单的实现逻辑,代码大概如下

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        CurrentTextBlock.Text = _list[_index].ToString();
    }

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        _count++;

        var number = _list[_index];

        e.Collection.Add(number);

        Clean(e.Collection);

        _index++;
        if (_index == _list.Length)
        {
            _index = 0;
        }
        CurrentTextBlock.Text = $"第 {_count} 次\r\n下一个 {_list[_index]}";
    }

    private static void Clean(ObservableCollection<int> collection)
    {
        while (collection.Count > 1)
        {
            var n1 = collection[^1];
            var n2 = collection[^2];

            if (n1 == n2)
            {
                collection.RemoveAt(collection.Count - 1);
                collection.RemoveAt(collection.Count - 1);
                collection.Add(n1 + n2);
            }
            else
            {
                break;
            }
        }

        if (collection[^1] == 1024 * 2)
        {
            collection.Clear();
        }
    }

    private int _index;
    private int _count;

    private readonly int[] _list = new int[] { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2 };
}

作为开发者,我玩着玩着就想着看程序自己玩,做成挂机游戏。于是再写点算法让程序自己玩好了,实现代码如下

    public MainWindow()
    {
        InitializeComponent();
        CurrentTextBlock.Text = _list[_index].ToString();

        Loaded += MainWindow_Loaded;
    }

    private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        while (Content is Grid grid)
        {
            var number = _list[_index];

            var maxValue = 1024;

            var cecaqemdarYefarqukeafai =
                grid.Children.OfType<CecaqemdarYefarqukeafai>()
                    .FirstOrDefault(t => t.Collection.Count > 0 && t.Collection[^1] == number);

            cecaqemdarYefarqukeafai ??= grid.Children.OfType<CecaqemdarYefarqukeafai>().Where(t => t.Collection.Count > 0 && t.Collection[^1] > number).MinBy(t => t.Collection[^1]);

            cecaqemdarYefarqukeafai ??= grid.Children.OfType<CecaqemdarYefarqukeafai>()
                .FirstOrDefault(t => t.Collection.Count == 0);

            cecaqemdarYefarqukeafai ??= grid.Children.OfType<CecaqemdarYefarqukeafai>().MinBy(t =>
            {
                if (t.Collection.Count > 0)
                {
                    var lastValue = t.Collection[^1];
                    if (lastValue > number)
                    {
                        return lastValue;
                    }
                    else
                    {
                        return maxValue;
                    }
                }

                return 0;
            });

            if (cecaqemdarYefarqukeafai is null)
            {
                continue;
            }

            cecaqemdarYefarqukeafai.Collection.Add(number);
            Clean(cecaqemdarYefarqukeafai.Collection);

            _index = Random.Shared.Next(_list.Length);
            _count++;
            CurrentTextBlock.Text = $"第 {_count} 次\r\n下一个 {_list[_index]}";

            await Task.Delay(300);
        }
    }

相信以上的逻辑大家看看也能明白,这是我随意写的简单算法,核心只是决定将数字放在哪个列表而已

完成之后的代码如下

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BawjadurbaWurahuwa;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        CurrentTextBlock.Text = _list[_index].ToString();

        Loaded += MainWindow_Loaded;
    }

    private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        while (Content is Grid grid)
        {
            var number = _list[_index];

            var maxValue = 1024;

            var cecaqemdarYefarqukeafai =
                grid.Children.OfType<CecaqemdarYefarqukeafai>()
                    .FirstOrDefault(t => t.Collection.Count > 0 && t.Collection[^1] == number);

            cecaqemdarYefarqukeafai ??= grid.Children.OfType<CecaqemdarYefarqukeafai>().Where(t => t.Collection.Count > 0 && t.Collection[^1] > number).MinBy(t => t.Collection[^1]);

            cecaqemdarYefarqukeafai ??= grid.Children.OfType<CecaqemdarYefarqukeafai>()
                .FirstOrDefault(t => t.Collection.Count == 0);

            cecaqemdarYefarqukeafai ??= grid.Children.OfType<CecaqemdarYefarqukeafai>().MinBy(t =>
            {
                if (t.Collection.Count > 0)
                {
                    var lastValue = t.Collection[^1];
                    if (lastValue > number)
                    {
                        return lastValue;
                    }
                    else
                    {
                        return maxValue;
                    }
                }

                return 0;
            });

            if (cecaqemdarYefarqukeafai is null)
            {
                continue;
            }

            cecaqemdarYefarqukeafai.Collection.Add(number);
            Clean(cecaqemdarYefarqukeafai.Collection);

            _index = Random.Shared.Next(_list.Length);
            _count++;
            CurrentTextBlock.Text = $"第 {_count} 次\r\n下一个 {_list[_index]}";

            await Task.Delay(300);


        }
    }

    private void CecaqemdarYefarqukeafai_OnClick(object? sender, CecaqemdarYefarqukeafai e)
    {
        _count++;

        var number = _list[_index];

        e.Collection.Add(number);

        Clean(e.Collection);

        _index++;
        if (_index == _list.Length)
        {
            _index = 0;
        }
        CurrentTextBlock.Text = $"第 {_count} 次\r\n下一个 {_list[_index]}";
    }

    private static void Clean(ObservableCollection<int> collection)
    {
        while (collection.Count > 1)
        {
            var n1 = collection[^1];
            var n2 = collection[^2];

            if (n1 == n2)
            {
                collection.RemoveAt(collection.Count - 1);
                collection.RemoveAt(collection.Count - 1);
                collection.Add(n1 + n2);
            }
            else
            {
                break;
            }
        }

        if (collection[^1] == 1024 * 2)
        {
            collection.Clear();
        }
    }

    private int _index;
    private int _count;

    private readonly int[] _list = new int[] { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2 };
}

本文以上代码放在 githubgitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 243d50c0b94013e5beb782e384c98a7b6e3f629d

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 243d50c0b94013e5beb782e384c98a7b6e3f629d

获取代码之后,进入 WPFDemo/BawjadurbaWurahuwa 文件夹,即可获取到源代码

进入文件夹之后使用 VisualStudio 2022 或更高版本的 VisualStudio 打开 BawjadurbaWurahuwa.sln 文件,然后试试按下 F5 进行构建且运行即可开始玩游戏

与WPF 做一个超级简单的 1024 数字接龙游戏相似的内容:

WPF 做一个超级简单的 1024 数字接龙游戏

这是一个我给自己做着玩的游戏,没有什么复杂的界面,就一些简单的逻辑 游戏的规则十分简单,那就是有多个列表。程序会给出一个数字,玩家决定数字放在哪个列表里面。如果放入列表里面的数字和列表里面最后一个数字相同,那两个数字将会叠加进行合并,合并两个 1024 将会自动清理掉整个列表 如下图,有 5 个列表

【炫丽】从0开始做一个WPF+Blazor对话小程序

大家好,我是沙漠尽头的狼。 .NET是免费,跨平台,开源,用于构建所有应用的开发人员平台。 本文演示如何在WPF中使用Blazor开发漂亮的UI,为客户端开发注入新活力。 注 要使WPF支持Blazor,.NET版本必须是 6.0 或更高版本,本文所有示例使用的.NET 7.0,版本要求见链接,截图

一款WPF的精简版MVVM框架——stylet框架的初体验(包括MVVM绑定、依赖注入等操作)

今天偶然知道一款叫做stylet的MVVM框架,挺小巧的,特别是它的命令触发方式,简单粗暴,让人感觉很巴适,现在我做一个简单的demo来顺便来分享给大家。 本地创建一个WPF项目,此处我使用.NET 8来创建。然后引用stylet最新的nuget包。 然后删掉App.xaml里面自带的启动项 删掉以

WPF使用Blazor的快速案例

下面我们将讲解在WPF中使用Blazor,并且使用Blazor做一些文件编辑操作,下面是需要用到的东西 - WPF - Blazor - Masa Blazor - Monaco ## 安装Masa Blazor模板 使用`CMD`指令安装模板 ```shell dotnet new install

循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(3)--自定义用户控件

在我们创建界面元素的时候,不管在Vue3+ElementPlus的前端上,还是Winform桌面端上,都是会利用自定义用户控件来快速重用一些自定义的界面内容,对自定义用户控件的封装处理,也是我们开发WPF应用需要熟悉的一环。本篇随笔继续深入介绍介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发,主要针对自定义用户控件的封装和使用做一些介绍。

记一次 .NET某工控WPF程序被人恶搞的 卡死分析

一:背景 1. 讲故事 这一期程序故障除了做原理分析,还顺带吐槽一下,熟悉我的朋友都知道我分析dump是免费的,但免费不代表可以滥用我的宝贵时间,我不知道有些人故意恶搞卡死是想干嘛,不得而知,希望后面类似的事情越来越少吧!废话不多说,我们来看看是如何被恶搞的。 二:WinDbg 分析 1. 程序是如

Azure DevOps(一)基于 Net6.0 的 WPF 程序如何进行持续集成、持续编译

一,引言 我们是否正在为如何快速的编译、部署客户端应用程序而烦恼?这也是博主最近遇到的问题。目前博主所在公司主要做项目级的定制化开发,多以 C/S 架构的 WPF 程序为主,每次到了协助开发团队给实施团队编译好的要测试程序包时,就会出现多人协助,编译、打包好的二进制程序包 pull 最新代码 ,以及

WPF复习知识点记录

# WPF复习知识点记录 由于近几年主要在做Web项目,客户端的项目主要是以维护为主,感觉对于基础知识的掌握没有那么牢靠,趁着这个周末重新复习下WPF的相关知识。 文章内容主要来自大佬刘铁锰老师的经典著作《深入浅出WPF》。 因为是复习,所以知识内容不会一一记录,如有需要了解更多可以看书中内容。 *

C# WPF 将第三方DLL嵌入 exe

没成功,只是做个记录,后面再研究 希望将第三方的 HandyControl.dll 嵌入到 exe 中,这样不用发多个文件给别人 ![image](https://img2023.cnblogs.com/blog/80824/202308/80824-20230804153348542-538869

循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(7) -- 图标列表展示和选择处理

我们在WPF应用端的界面中,使用lepoco/wpfui 来做主要的入口框架,这个项目它的菜单内置了不少图标,我们需要在动态菜单的配置中,使用它作为图标的展示处理,本篇随笔介绍如何基于图标枚举集合进行图标的展示和选择处理。并扩展到Font-Awesome-WPF的处理进行展示和选择。