前言

在使用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)模式中,使用命令而不是事件的主要原因包括以下几点:

  1. 解耦:命令将用户界面(View)与业务逻辑(ViewModel)分离,使得两者之间的耦合度降低。这有助于提高代码的可维护性和可测试性。
  2. 可测试性:命令使得ViewModel中的逻辑更容易进行单元测试,因为命令可以独立于UI进行测试,而事件则需要依赖于特定的UI元素。
  3. 一致性:命令提供了一种一致的方式来处理用户操作,无论这些操作是通过按钮点击、菜单选择还是其他UI元素触发的。
  4. 数据绑定:命令可以通过数据绑定直接与UI元素关联,这使得ViewModel可以控制UI元素的启用和禁用状态,而无需直接操作UI元素。
  5. 复用性:命令可以在不同的UI元素之间复用,而事件通常与特定的UI元素绑定,复用性较差。

通过使用命令,开发者可以更好地遵循MVVM模式的原则,实现更清晰、更模块化的代码结构。

以上就是通过这个Demo,我们可以简单了解的一些内容,希望对你有所帮助。

WPF/C#:在DataGrid中显示选择框的更多相关文章

  1. WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮

    原文:WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮 在边框中加入一些元素,在应用程序的界面设计中,已经开始流行起来.特别是在浏览器(Crome,IE,Firefox,Opera)中都有应用. ...

  2. cocos2dx2.2.2登录场景中Checkbox选择框的实现

    在前两篇文章中,我们介绍了在注册场景中需要用到的输入框及弹出框的实现方式,这两篇文章中介绍的内容在登录场景同样会用到.而我们经常会在登录场景中见到的另一种元素就是自动登录或者记住密码的Checkbox ...

  3. Unity编辑器扩展Texture显示选择框

    学习NGUI插件的时候,突然间有一个问题为什么它这些属性可以通过弹出窗口来选中呢? 而我自己写的组件只能使用手动拖放的方式=.=. Unity开发了组件Inspector视图扩展API,如果我们要写插 ...

  4. 如何在VBS脚本中显示“选择文件对话框”或“选择目录对话框”

    .选择文件[XP操作系统,不能用于Win2000或98],使用“UserAccounts.CommonDialog”对象向用户显示一个标准的“文件打开”对话框 Set objDialog = Crea ...

  5. [WPF]GridView或DataGrid中自定义样式:依据某一列设定其对应行的样式(背景色,字体等)

    附效果照一张: 本方法使用StyleSelector来 获得依据自定义逻辑的style. ① class ConditionalStyleSelector : StyleSelector { publ ...

  6. 如何在vue+element中实现选择框和穿梭框的根据拼音以及拼音首字母以及汉字的模糊搜索

    1.汉字: 直接添加对应的 filterable     2.拼音: 穿梭框和选择器的实现方式有所不同   选择器:   <1>下载pinyin-match:   npm i --save ...

  7. 03 将MDB文件在DATAGRID中显示

    附件:http://files.cnblogs.com/xe2011/MDB_BindingSource.rar using System; using System.Collections.Gene ...

  8. 如何在easyui datagrid 中显示外键的值

    1.需要在角色列表显示角色类别的值,而角色类别是外键,关联数据字典,明细见下图: 2.代码如下: columns: [[ { field: 'ck', checkbox: true, align: ' ...

  9. 左右选择框 js插件

    随着项目的进展,测试工程师在更多的浏览器中兼容性测试中,发现有些浏览器不支持option的触发事件,这就造成了先前一篇博文bootstrap 左右框多项选择示例 中左右选择框的失效,于是我就由原先的s ...

  10. 修改页面中显示出需要修改的数据(包括select选择框复显示)

    页面中需要用到某个对象时,在底层代码中赋值,然后页面用java代码进行获取调用 如下截图: select复显示:根据后台方法赋值选择框 ,并设置初始值 按钮及选择框的禁用(五种方法): 方法一: $( ...

随机推荐

  1. [FAQ] Solidity 并发执行 ? 重入攻击 ?

    Solidity 实现的合约中,函数操作都是原子操作,旷工本地执行,取得共识后发布到区块链上. 实际发布到区块链上的不存在并发,全节点同步状态到本地. Solidity 中有三种方式进行转账,addr ...

  2. win10 uwp 笔迹书写预测 墨迹书写加速

    在 UWP 的 InkCanvas 里自带了预测书写轨迹的功能,开启此功能可以进行书写预测,从而减少书写延迟.本文将告诉大家如何在 UWP 的 InkCanvas 里开启笔迹书写预测功能 在 UWP ...

  3. SQL中常用的字符串REPLACE函数和LEN函数详解!

    首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...

  4. cesium教程9-加载倾斜摄影并解决高度问题

    无人机航拍的倾斜摄影,用照片和视频处理生成三维模型,一般照片都带有坐标信息,所以一般都能定位的比较准确,但是经常会出现高度偏差,这个时候就需要特殊处理了. 今天航拍建模的效果如下: 这个建模没有裁剪, ...

  5. 传统css布局方案(position,float,line-height等配合)

    一.display display 是 css 布局中很重要的一个属性,它定义了元素生成的显示框类型,常见的几个属性值有:block.inline.inline-block.inherit.none. ...

  6. C语言:约瑟夫问题——使用循环链表解决

    传说有30个乘客同乘一条船,因为严重超载,加上风浪水作,危险万分.船长告诉乘客,只有将全船一半的乘客投入海 中,其余人才能幸免于难.他们约定了一个规则:30个人围成一圈,由第一个人数起,依次报数,数到 ...

  7. C 语言编程 — 宏定义与预处理器指令

    目录 文章目录 目录 前文列表 宏 预处理器 预处理器指令 预处理器指令示例 预定义宏 预处理器指令运算符 宏延续运算符 字符串常量化运算符 标记(Token)粘贴运算符 defined() 运算符 ...

  8. spring boot 整合mybatis 配置多数据源 数据源切换和多数据源的事务

    因为项目中用到了多数据源 不可避免的会有各种各样的问题列一下最主要的问题: 1 如何配置多数据源???2 spring项目中多数据源无法切换???3 操作了2个或者2个以上数据库的数据无法保证事务的一 ...

  9. WPF使用WPFMediaKit/AForge调用摄像头示例 .net core 8.0 也支持

    调用摄像头使我们经常会用到的一个功能,可以根据摄像头捕捉到的图像进行分析处理来做很多的东西,比如电子档案.图像识别.AI分析等等. 本示例中主要介绍Nuget最常用的两个调用摄像头的轮子 WPFMed ...

  10. liunx查看nginx 进程

    ChatGPT4.0国内站点: https://www.weijiwangluo.com/talk 要查看nginx进程,可以使用以下命令: ps -ef | grep nginx 这个命令会列出当前 ...