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模式:

image-20240620085658595

创建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命令即可。

实现的效果如下所示:

image-20240620095433218

实现了添加选择框的效果,但是会觉得一个一个点太麻烦了,这时候就可以增加全选与取消全选的功能。

在菜单中添加这两项功能:

 <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,我们可以简单了解的一些内容,希望对你有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/729659.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【51单片机】按键的操作

文章目录 前言读取按键的原理proteus仿真示例代码 总结 前言 在现代电子产品中&#xff0c;按键是用户与设备之间交互的重要组成部分。它们允许用户通过简单的按下来触发特定的操作或命令。在微控制器的背景下&#xff0c;按键的设计和操作对于确保设备的响应性和用户体验至关…

CSS新手入门笔记【导入方法、选择器介绍、选择器优先级、属性详细介绍、盒子模型】

目录 一、目的与优势二、CSS导入方式三、语法结构四、选择器类型基本选择器组合选择器伪类与伪元素属性选择器 六、选择器优先级总结 六、CSS属性1. 字体与文本属性2. 背景属性3. 尺寸与盒模型属性4. 布局与定位5. 列表样式6. 边框与轮廓7. 文本装饰与效果8. 动画与过渡9. 伪类…

RocketMQ-记一次生产者发送消息存在超时异常

目录 1、背景说明 2、排查 2.1、防火墙 2.2、超时时间设置 2.3、服务器资源检查 2.3.1、内存、CPU等 2.3.2、磁盘空间 ​编辑 2.3.3、检查文件描述符 2.3.4、swap区 3、增加swap空间 3.1、创建目录 3.2、格式化 3.3、启动swap 3.4、查看效果 1、背景说明 在一次…

Harbor 不同模块作用以及持久化数据大小建议

目录 1. Harbor 组件1.1 Registry (Harbor Registry)1.2 Database (PostgreSQL)1.3 Jobservice1.4 Chartmuseum1.5 Redis1.6 Trivy 2. 示例 values.yaml3. 总结 搭建环境 使用 NFS 作为持久化存储使用 Helm 在 k8s 上进行搭建 在使用 Helm 安装 Harbor 并配置持久化存储时&am…

ai assistant激活成功后,如何使用

ai assistant激活成功后&#xff0c;如图 ai assistant渠道&#xff1a;https://web.52shizhan.cn/activity/ai-assistant 在去年五月份的 Google I/O 2023 上&#xff0c;Google 为 Android Studio 推出了 Studio Bot 功能&#xff0c;使用了谷歌编码基础模型 Codey,Codey 是…

Redis-数据类型-zset

文章目录 1、查看redis是否启动2、通过客户端连接redis3、切换到db4数据库4、将一个或多个member元素及其score值加入到有序集key当中5、升序返回有序集key6、升序返回有序集key&#xff0c;让分数一起和值返回的结果集7、降序返回有序集key&#xff0c;让分数一起和值返回到结…

海外仓系统有哪些模块:WMS海外仓系统完整功能清单

虽然说现在市面上的海外仓系统非常多&#xff0c;各有特色&#xff0c;不过在功能模块的设计上&#xff0c;其实殊途同归&#xff0c;只是各有侧重点而已。 作为海外仓企业&#xff0c;想选择一套适合自己的WMS海外仓系统&#xff0c;首先就要了解系统标准的功能模块都有什么。…

Typora v1.8.6解锁版安装教程 (轻便简洁的Markdown编辑器)

前言 Typora是一款轻便简洁的Markdown编辑器&#xff0c;支持即时渲染技术&#xff0c;这也是与其他Markdown编辑器最显著的区别。即时渲染使得你写Markdown就想是写Word文档一样流畅自如&#xff0c;不像其他编辑器的有编辑栏和显示栏。 一、下载地址 下载链接&#xff1a;…

Redis单例部署

目录 1. 概述2. 参考3. 环境4. 部署4.1 操作系统4.1.1 修改系统参数4.1.2 关闭透明大页内存4.1.3 修改系统限制 4.2 安装Redis4.2.1 下载Redis4.2.2 创建redis账号4.2.3 添加Redis环境变量4.2.4 创建Redis使用目录4.2.5 安装Redis4.2.6 手动修改配置文件&#xff08;**可跳过&a…

2025天津数控机床展(天津工业展)

2025第21届天津工博会—机床展 时间&#xff1a;2025年3月6-9日 地点&#xff1a;国家会展中心&#xff08;天津&#xff09; 达成交易&#xff0c;是我们唯一的追求&#xff01; Dealing Is Our Top Pursuit. 主办单位 振威会展集团 中国机械工业联合会 中国国际贸易促…

名称申请不了商标,可以受保护不!

前几天个网友说要申请注册个商标名称&#xff0c;发来名称让普推商标知产老杨帮忙检索了下&#xff0c;发现有同名的被驳回&#xff0c;而且是做过驳回复审被驳回&#xff0c;而且是绝对理由驳回的&#xff0c;易使消费者对商品的品质等特点产生误认&#xff0c;不得作为商标使…

如何开发一个项目脚手架cli

目录 背景正文unbuildpromptsprogresskolorist 设置打包命令npm execnpxnpm init/ npm create/ npm innit 使用最后 背景 随着团队项目类型越来越多&#xff0c;方便后续快速去开发项目&#xff0c;会出现各种类型的项目模版项目。 这样开发只需要通过脚手架选择自己需要的项目…

数据采集之二主一从,485总线共享器

产品概述 485总线共享器示意图 功能示意图 DAQ-GP-485HUB是上海数采物联网推出的一款 RS485总线多路复用共享数据处理器&#xff0c;是一款高性能的通讯设备&#xff0c;专门针对两台主机和 一台从机通讯时导致的数据冲突而设计。在实际工业控制和监控场景中&#xff0c;多个主…

Java宝藏实验资源库(3)类

一、实验目的 理解面向对象程序的基本概念。掌握类的继承的实现机制。熟悉类中成员的访问控制方法。熟悉ArrayList类的使用。 二、实验内容、过程及结果 *9.5Programming Exerc ise the GregorianCal endar class) Java API has the GregorianCalendar class in the java. uti…

算法008:四数之合

四数之和. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/4sum/description/ 在前面的两个题中&#xff0c;我们已经完成了两数之和和三数之和&#xff0c;到本题四…

基于51单片机的函数信号发生器

基于51单片机函数信号发生器 &#xff08;仿真&#xff0b;程序&#xff0b;原理图&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.LCD1602液晶显示波形种类和频率值&#xff08;10-100HZ&#xff09;&#xff1b; 2.按键设置波形种类和设定频率步进值…

Notepad++插件 Hex-Edit

Nptepad有个Hex文件查看器&#xff0c;苦于每次打开文件需要手动开插件显示Hex&#xff0c;配置一下插件便可实现打开即调用 关联多个二进制文件&#xff0c;一打开就使用插件的方法&#xff0c;原来是使用空格分割&#xff01;&#xff01;&#xff01;

螺蛳粉店外卖配送小程序商城的效果为何

螺蛳粉是广西地区的特色美食&#xff0c;在当地有着大量实体餐饮店或品牌商&#xff0c;其单品消费率非常高&#xff0c;在外地也不乏自创品牌或加盟店等&#xff0c;其特殊的味道及吸引力也同样复购率高&#xff0c;客户除了线下到店外&#xff0c;也会购买袋/桶装螺蛳粉到家自…

【无线感知】【P4】无线感知手势识别- WIFI 感知边界

前言&#xff1a; 这篇是北大2022 在Ubicomp 上面的论文 《placement Matters&#xff1a; understanding the Effects of Device placements for WiFi Sensing》 放置很重要&#xff1a;了解设备放置对WiFi传感的影响 目录&#xff1a; 简介 感知质量定义&#xff08;SSNR…

Bayanay:一款基于Python开发的无线网络安全研究工具

关于Bayanay Bayanay是一款基于纯Python开发的无线网络安全研究工具&#xff0c;在该工具的帮助下&#xff0c;无论你身处何地&#xff0c;都可以轻松地对周围地区的无线网络安全状况进行研究与分析。 该工具可以通过使用HTML5的地理位置定位功能并结合Scapy获取到的SSID信息…