WPF/C#:在DataGrid中显示选择框
前言
在使用WPF的过程中可能会经常遇到在DataGrid的最前或者最后添加一列选择框的需求,今天跟大家分享一下,在自己的项目中是如何实现的。
整体实现效果如下:

如果对此感兴趣,可以接下来看具体实现部分。
实践
假设数据库中的模型如下:
public class Person
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Home { get; set; }
}
但是要实现这个需求,需要为模型增加一个bool类型的属性表示是否选中,但是这个属性只是为了在界面上显示,根本就不需要存入数据库,也就是说数据库中的模型与MVVM模式中的模型可能会有一些不同,这是很常见的一种情况,因为为了使用MVVM模式,模型也要实现INotifyPropertyChanged,如果数据库模型与MVVM中的模型是同一个的话,会让模型结构变得不直观。
这时候可以建立一个PersonViewModel类,如下所示:
public partial class PersonViewModel : ObservableObject
{
[ObservableProperty]
private int id;
[ObservableProperty]
private string? name;
[ObservableProperty]
private string? home;
[ObservableProperty]
private bool isSelected;
public PersonViewModel(Person person)
{
this.Id = person.Id;
this.Name = person.Name;
this.Home = person.Home;
this.IsSelected = false;
}
}
这里使用了CommunityToolkit.Mvvm包简化实现MVVM模式:

创建ViewModel:
public partial class DataGridDemoViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<PersonViewModel> people;
public DataGridDemoViewModel()
{
People = new ObservableCollection<PersonViewModel>();
}
[RelayCommand]
private void GetPeople()
{
var people = GetPeopleFromDataBase();
var peopleViewModels = people.Select(n => new PersonViewModel(n));
People.AddRange(peopleViewModels);
}
List<Person> GetPeopleFromDataBase()
{
var People = new List<Person>()
{
new Person { Id = 1, Name = "小一", Home = "北京" },
new Person { Id = 2, Name = "小二", Home = "上海" },
new Person { Id = 3, Name = "王五", Home = "广州" },
new Person { Id = 4, Name = "小红", Home = "深圳" },
new Person { Id = 5, Name = "小绿", Home = "杭州" },
new Person { Id = 6, Name = "小刚", Home = "南京" },
};
return People;
}
}
首先使用GetPeopleFromDataBase模拟从数据库中获取类型为List<Person>的数据:
List<Person> GetPeopleFromDataBase()
{
var People = new List<Person>()
{
new Person { Id = 1, Name = "小一", Home = "北京" },
new Person { Id = 2, Name = "小二", Home = "上海" },
new Person { Id = 3, Name = "王五", Home = "广州" },
new Person { Id = 4, Name = "小红", Home = "深圳" },
new Person { Id = 5, Name = "小绿", Home = "杭州" },
new Person { Id = 6, Name = "小刚", Home = "南京" },
};
return People;
}
为了在页面上实现增减通知,一般在ViewModel中使用的是ObservableCollection<T>而不是List<T>,因此需要一个转换:
var people = GetPeopleFromDataBase();
var peopleViewModels = people.Select(n => new PersonViewModel(n));
由于ObservableCollection<T>没有实现AddRange方法,可以使用扩展方法写一下。
扩展方法(Extension Methods)是C#中的一种特殊方法,允许向现有类型添加新方法,而无需修改原始类型的代码或创建派生类型。扩展方法必须在静态类中定义,并且第一个参数前带有this关键字,指定要扩展的类型。这使得可以为内置类型或第三方库中的类型添加自定义方法,从而提高代码的可读性和重用性。扩展方法的使用方式与实例方法相同,可以通过实例直接调用。
添加的扩展方法如下所示:
public static class ObservableCollectionExtensions
{
public static void AddRange<T>(this ObservableCollection<T> collection, IEnumerable<T> range)
{
foreach (var item in range)
{
collection.Add(item);
}
}
}
现在来创建View:
<StackPanel>
<StackPanel>
<TabControl Margin="0,8,0,0">
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Margin="0,0,6,0" Symbol="Home24" />
<TextBlock Text="DataGrid添加选择框Demo" />
</StackPanel>
</TabItem.Header>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Menu FontSize="14">
<ui:MenuItem Header="操作菜单" Icon="{ui:SymbolIcon ToolBox28}">
<ui:MenuItem Header="获取People集合"
Icon="{ui:SymbolIcon Search16}"
Command="{Binding GetPeopleCommand}"/>
</ui:MenuItem>
<Separator />
</Menu>
</StackPanel>
<StackPanel>
<ui:DataGrid Height="400" ItemsSource="{Binding People}">
</ui:DataGrid>
</StackPanel>
</StackPanel>
</TabItem>
</TabControl>
</StackPanel>
</StackPanel>
<ui:DataGrid Height="400" ItemsSource="{Binding People}">
</ui:DataGrid>
直接将ItemsSource绑定至People集合就行了。
<ui:MenuItem Header="获取People集合"
Icon="{ui:SymbolIcon Search16}"
Command="{Binding GetPeopleCommand}"/>
绑定GetPeopleCommand命令即可。
实现的效果如下所示:


实现了添加选择框的效果,但是会觉得一个一个点太麻烦了,这时候就可以增加全选与取消全选的功能。
在菜单中添加这两项功能:
<Menu FontSize="14">
<ui:MenuItem Header="操作菜单" Icon="{ui:SymbolIcon ToolBox28}">
<ui:MenuItem Header="获取People集合"
Icon="{ui:SymbolIcon Search16}"
Command="{Binding GetPeopleCommand}"/>
<ui:MenuItem Header="全部选中"
Icon="{ui:SymbolIcon SelectAllOn24}"
Command="{Binding SelectAllPeopleCommand}"/>
<ui:MenuItem Header="取消全部选中"
Icon="{ui:SymbolIcon SelectAllOff24}"
Command="{Binding UnselectAllPeopleCommand}"/>
</ui:MenuItem>
<Separator />
</Menu>
在ViewModel中添加这两个命令:
[RelayCommand]
private void SelectAllPeople()
{
foreach (var person in People)
{
person.IsSelected = true;
}
}
[RelayCommand]
private void UnselectAllPeople()
{
foreach (var person in People)
{
person.IsSelected = false;
}
}
现在在看看看效果:

回顾
通过这个Demo,总体上学习了MVVM模式的简单使用。MVVM中的Model不一定就是数据库的Model可以自己根据页面显示的需要增减属性。为了简化MVVM模式的实现,可以借助一些MVVM库,本文使用的是CommunityToolkit.Mvvm,使用了ObservableObject基类、[ObservableProperty]特性与[RelayCommand]特性。当发现类型缺少我们需要的方法时,可以使用扩展方法写一个。为了减少和页面耦合,MVVM模式中使用命令而不是事件。以下是大模型的回答,可以简单参考一下:
在WPF的MVVM(Model-View-ViewModel)模式中,使用命令而不是事件的主要原因包括以下几点:
- 解耦:命令将用户界面(View)与业务逻辑(ViewModel)分离,使得两者之间的耦合度降低。这有助于提高代码的可维护性和可测试性。
- 可测试性:命令使得ViewModel中的逻辑更容易进行单元测试,因为命令可以独立于UI进行测试,而事件则需要依赖于特定的UI元素。
- 一致性:命令提供了一种一致的方式来处理用户操作,无论这些操作是通过按钮点击、菜单选择还是其他UI元素触发的。
- 数据绑定:命令可以通过数据绑定直接与UI元素关联,这使得ViewModel可以控制UI元素的启用和禁用状态,而无需直接操作UI元素。
- 复用性:命令可以在不同的UI元素之间复用,而事件通常与特定的UI元素绑定,复用性较差。
通过使用命令,开发者可以更好地遵循MVVM模式的原则,实现更清晰、更模块化的代码结构。
以上就是通过这个Demo,我们可以简单了解的一些内容,希望对你有所帮助。
WPF/C#:在DataGrid中显示选择框的更多相关文章
- WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮
原文:WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮 在边框中加入一些元素,在应用程序的界面设计中,已经开始流行起来.特别是在浏览器(Crome,IE,Firefox,Opera)中都有应用. ...
- cocos2dx2.2.2登录场景中Checkbox选择框的实现
在前两篇文章中,我们介绍了在注册场景中需要用到的输入框及弹出框的实现方式,这两篇文章中介绍的内容在登录场景同样会用到.而我们经常会在登录场景中见到的另一种元素就是自动登录或者记住密码的Checkbox ...
- Unity编辑器扩展Texture显示选择框
学习NGUI插件的时候,突然间有一个问题为什么它这些属性可以通过弹出窗口来选中呢? 而我自己写的组件只能使用手动拖放的方式=.=. Unity开发了组件Inspector视图扩展API,如果我们要写插 ...
- 如何在VBS脚本中显示“选择文件对话框”或“选择目录对话框”
.选择文件[XP操作系统,不能用于Win2000或98],使用“UserAccounts.CommonDialog”对象向用户显示一个标准的“文件打开”对话框 Set objDialog = Crea ...
- [WPF]GridView或DataGrid中自定义样式:依据某一列设定其对应行的样式(背景色,字体等)
附效果照一张: 本方法使用StyleSelector来 获得依据自定义逻辑的style. ① class ConditionalStyleSelector : StyleSelector { publ ...
- 如何在vue+element中实现选择框和穿梭框的根据拼音以及拼音首字母以及汉字的模糊搜索
1.汉字: 直接添加对应的 filterable 2.拼音: 穿梭框和选择器的实现方式有所不同 选择器: <1>下载pinyin-match: npm i --save ...
- 03 将MDB文件在DATAGRID中显示
附件:http://files.cnblogs.com/xe2011/MDB_BindingSource.rar using System; using System.Collections.Gene ...
- 如何在easyui datagrid 中显示外键的值
1.需要在角色列表显示角色类别的值,而角色类别是外键,关联数据字典,明细见下图: 2.代码如下: columns: [[ { field: 'ck', checkbox: true, align: ' ...
- 左右选择框 js插件
随着项目的进展,测试工程师在更多的浏览器中兼容性测试中,发现有些浏览器不支持option的触发事件,这就造成了先前一篇博文bootstrap 左右框多项选择示例 中左右选择框的失效,于是我就由原先的s ...
- 修改页面中显示出需要修改的数据(包括select选择框复显示)
页面中需要用到某个对象时,在底层代码中赋值,然后页面用java代码进行获取调用 如下截图: select复显示:根据后台方法赋值选择框 ,并设置初始值 按钮及选择框的禁用(五种方法): 方法一: $( ...
随机推荐
- [FAQ] Vmmem 内存占用高的问题 -Win10 -WLS2
1按下Windows + R 键,输入 %UserProfile% 并运行进入用户文件夹 2新建文件 .wslconfig ,然后记事本编辑 3 填入以下内容并保存, memory为系统内存上限,这里 ...
- 8.k8s之调动pod到指定节点与创建多容器pod并查找pod日志
官方文档:将pod分配给节点题目1:调度pod到指定节点 设置配置环境kubectl config use-context k8s 按如下要求创建并调度一个pod: - 名称:nginx-kusc00 ...
- CSP-S2023游记
不知不觉也高二了呢,最后一年OI了. Day -?? 过了初赛.没什么难度. Day -4 模拟赛挂分. RP++. Day -3 模拟赛挂分. RP++. Day -2 没挂分--?换数据了,又挂了 ...
- R3_Elasticsearch Index Setting
索引的配置项按是否可以更改分为static属性与动态配置,所谓的静态配置即索引创建后不能修改.目录如下:生产环境中某索引结构(7.X后有变化) 索引静态配置 1.分片与压缩 index.number_ ...
- 快速入门一篇搞定RocketMq-实现微服务实战落地
1.RocketMq介绍 RocketMQ起源于阿里巴巴,最初是为了解决邮件系统的高可靠性和高性能而设计的.在2016年开源分布式消息中间件,并逐渐成为Apache顶级项目.现在是Apache的一个顶 ...
- STM32F1和STM32F4系列DMA的不同之处——对STM32的DMA的工作机制的一些理解
喜欢用STM32的DMA功能.一方面STM32的DMA和MPU的DMA一样,可以提高数据传输效率.另一方面,作为一种MCU上的DMA,它可以提高针对外设(peripheral)的数据传输的实时性,改变 ...
- ssh端口转发实际应用
目录 1 ssh本地端口转发 2 ssh远程端口转发 3 跨网络访问(网关功能) 4 动态端口转发(KX上网) SSH 会自动加密和解密所有 SSH 客户端与服务端之间的网络数据.而且,SSH 还能够 ...
- Linux(四):Linux的打包和压缩详解
关于Linux的文件操作,这里汇总一下打包和压缩的一些命令,以及命令使用的详情. 打包(归档)和压缩 归档,也称为打包,指的是一个文件或目录的集合,而这个集合被存储在一个文件中.归档文件没有经过压缩, ...
- Calcite sql2rel 过程
sql2rel的过程是将SqlNode 转化成RelNode的过程 在 SqlToRelConverterTest中添加样例测试 @Test void testScan() { String sql ...
- Java面试题:让依赖注入变得简单,面对@Autowired和@Resource,该如何选择?
@Autowired和@Resource都是Java Spring框架中的注解,用于实现依赖注入(DI)和控制反转(IoC).它们的区别主要在以下三个方面: 源头不同 @Autowired是Spri ...