2023年7月19日发(作者:)
有关WPF中DataGrid控件的基础应⽤总结基础说明DataGrid是WPF提供的基础控件,它可以⾮常轻松的呈现出⼀张表格,本⽂章会按照从易到难的顺序依次将DataGrid的使⽤⽅法进⾏解说,除了MSDN上给出的最基本的例⼦之外,给出了三个⽐较常见的在真实使⽤场景下使⽤的例⼦,这三个例⼦已经基本覆盖了我们能够遇到的⼤部分使⽤场景了。基础实例:MSDN上,使⽤DataGrid绑定⼀个数据模型在MSDN上,可以⾮常轻松的找到有关于对DataGrid控件进⾏数据绑定的⽅法,微软提供的绑定⽅法是这样的:执⾏步骤:1、有⼀个已经定义好的类型:public class Customer{ public string FirstName { get; set; } public string LastName { get; set; } public Uri Email { get; set; } public bool IsMember { get; set; }}2、编写⼀个XAML的DataGrid控件在这⾥,DataGrid关联数据⽐较灵活,就不⼀⼀列举了,下边贴出的代码只使⽤了其中⼀种关联⽅式:1. 可以像例⼦⾥⼀样:先将ItemsSource使⽤Binding空出path属性,然后使⽤DataContext指定数据源2. 也可以在前端不指定ItemsSource,然后直接在C#代码中指定ItemsSource:ource = list;3. 也可以直接在XAML前端直接指定容器
CellEditingTemplate="{StaticResource ResourceKey = cellEditingTemplate}"/>
可触发的命令:显⽰消息内容; /// private ICommand mShowCommand; public ICommand ShowCommand { get { if (mShowCommand == null) { mShowCommand = new RelayCommand(() => { ExecuteAction(); }, () => CanExecuteFunc()); } return mShowCommand; } } private bool CanExecuteFunc() { return true; } private void ExecuteAction() { ine("Content is" + this.m_content); ine("Content is" + this.m_content); foreach(var iter in this.m_content_detail) { ine("Content Detail is " + iter); } } ///
消息编号; /// private string No; public string m_No { get { return No; } set { No = value; } } ///
时间戳; /// private DateTime time; public DateTime m_time { get { return time; } set { time = value; } } ///
消息内容A; /// private string content; public string m_content { get { return content; } set { content = value; } } private List
///
消息的源IP地址; /// private string source; public string m_source { get { return source; } set { source = value; } } ///
消息的⽬的IP地址; /// private string dest; public string m_dest { get { return dest; } set { dest = value; } }}public class RelayCommand : ICommandpublic class RelayCommand : ICommand{ private Action mExecuteAction; //
执⾏命令; private Func
命令是否可以执⾏; public RelayCommand(Action executeAction, Func
public bool CanExecute(object parameter) { return (); } public void Execute(object parameter) { (); } public event EventHandler CanExecuteChanged;
}3、定义⼀个与DataGrid控件直接交互的VM层,⽤来控制控件的显⽰内容这种设计思路是MVVM框架的思路,可以⽐较好的解耦前端WPF层(View层)与后端数据模型(Model层),在VM层(ViewModel),专门⽤⼀个List或者ObservableCollection容器保存想要在前端DataGrid中显⽰的容器列表public class MessageVM{ //
存放所有消息内容的地⽅; private volatile ObservableCollection
使⽤⼀个线程更新DataGrid控件Task a = new Task(()=>{ int temp = 0; while(true) { temp = temp + 1; (, (Action)delegate { m_(new MessageModel() { m_No = ng(), m_time = , m_content = "content", m_source = "172.27.0.1", m_dest = "172.27.0.2"
}); }); (1233); }});();最终,呈现的效果如下,在点击消息内容单元格内的"…"按钮后,既可以触发查看内容的详细信息这个⽅法的主要核⼼点就在于使⽤了DataTemplate数据模板,这个数据模板可以很好的帮助你在DataGrid表的单元格内放置任意你想要的形态,但这样做也会带来⼀些问题:1. 如果只是简单的编辑表格,或者对表格本⾝进⾏操作,DataTemplate就⽆能为⼒了:1. ⽐如编辑单元格2. ⽐如⿏标滑过表格或单元格时,有悬浮窗提⽰信息3. 等等这样针对表格,某个单元格本⾝,⽽不是针对某个单元格中的内容操作2. 这个表格仍然没有解决前端代码被写死,Model和View必须⼀⼀对应的问题应⽤实例2:使⽤DataGrid⾃带的事件对表格进⾏操作以上那种形式,是通过⾃定义单元格来解决⼤部分对表格操作的需求,但是,如同上例,简单操作单元格的话,⽤⿏标或者控件本⾝事件就好了,在每个单元格内都增加⼀个按钮也⽐较难看,况且⾃定义DataTemplate针对整张表格的操作也时⽆法实现。所以⼤部分的基本的操作,利⽤DataGrid本⾝⾃带的事件实现就好了执⾏步骤:1、在前端定义⼀个表格这⾥注意⼀点:将SelectionUnit=“Cell” SelectionMode="Single"这两个属性设定后,就可以对某个单元格进⾏操作了,默认情况下,点击DataGrid后,默认是选中整⾏的
向单元格填写⾃定义个类型; public GridCell column2 { get; set; } //
向单元格填写⾃定义个类型; public GridCell column3 { get; set; } //
向单元格填写⾃定义个类型; //
当表格控件被编辑时,会调⽤单元格⾃⾝实例对应的函数; public void JudegePropertyCall_CellEditing(string colHeader) { switch(colHeader) { case "Column1": gCalback(); break; case "Column2": gCalback(); break; case "Column3": gCalback(); break; default: break; } }}4、最后在逻辑处理代码中填充数据和对应的事件ObservableCollection
以下是表格事件;erDataGrid_ingEdit += CustomerDataGrid_AddEvent_BeginningEdit; //
事件⼀:单元格开始编辑事件;erDataGrid_ionChanged += CustomerDataGrid_AddEvent_SelectionChanged; //
事件⼆:单元格选择出现变化时;erDataGrid_us += CustomerDataGrid_AddEvent_GotFocus; //
事件三:DataGrid表格点击单元格获取焦点时;//
以下是⿏标事件;erDataGrid_ove += CustomerDataGrid_AddEvent_MouseMove; //
事件四:⿏标移动到某个单元格上时触发(实验函数增加了⿏标拖动效果);erDataGrid_seCapture += CustomerDataGrid_AddEvent_GotMouseCapture; //
事件五:使⽤这个事件事件⿏标拖拽更加稳定;erDataGrid_eftButtonDown += CustomerDataGrid_AddEvent_MouseLeftButtonDown; //
事件六:⿏标左键点击事件,这个事件只针对DataGrid整个表格;erDataGrid_nter += CustomerDataGrid_AddEvent_MouseEnter; //
事件七:⿏标进⼊整个表格时触发,且只触发⼀次;//
另⼀个元素接收⿏标拖拽事件;rop = true; += ReceiveDataLabel_Drop;列出⽐较常⽤的事件:由于MSDN上边,有关于事件列表中的描述都⽐较晦涩难懂,所以在此列出⼀些⽐较常见的表格操作系列事件(未完待续)⿏标操作系列事件1. MouseMove1. 当⿏标进⼊到DataGrid控件真实填充过的单元格后,⿏标每移动到某个元素的时候,都会触发这个事件2. 带有两个⼊参,⼏个⽐较重要的可以获取的参数:1. object sender:DataGrid本⾝2. MouseEventArgs e:alSource is DataGridCell3. 获取表格当中的元素类型:(alSource as DataGridCell).DataContext2. GotMouseCapture1. 当⿏标进⼊到DataGrid控件真实填充过的单元格后,⿏标每点击某个单元格的时候,就会触发这个事件2. 带有两个⼊参,⼏个⽐较重要的可以获取的参数:1. object sender:DataGrid本⾝2. alSource is DataGrid3. 获取表格当中的元素类型:foreach (var iter in (alSource as DataGrid).SelectedCells)以上两个⿏标事件的作⽤区域见下图:即有真实填充数据的区域应⽤场景1:MouseMove和GotMouseCapture可以⽤来实现⿏标拖拽事件使⽤Drop就可以实现⿏标拖拽的起点,使⽤[控件名称].Drop += [funcCallback]实现接收⿏标拖拽的事件。具体可参见GitHub中的源码3. MouseEnter1. 当⿏标进⼊到整个DataGrid表格的时候,会触发⼀次,且不会重复触发,直到⿏标离开DataGrid控件后,再次进⼊之后,才会再次触发2. 带有两个⼊参,三个可以获取的⽐较重要的参数:1. sender:DataGrid本⾝2. is DataGrid本⾝3. alSource is DataGrid本⾝MouseEnter⿏标事件的作⽤区域为DataGrid整表,见下图:4. MouseLeftButtonDown1. 当⿏标在DataGrid没有填充数据的单元格处,发⽣了⿏标左键按下的时候触发的事件2. 带有两个参数,两个可以获取的⽐较重要的参数:1. sender is DataGrid本⾝2. is DataGrid本⾝MouseLeftButtonDown⿏标事件的作⽤区域为DataGrid没有填充单元格的区域,见下图:应⽤实例3:通过动态类型实现⼀个动态DataGrid表格(即可以填充任何数据类型)以上两种实例的做法的核⼼思想是:每⼀个DataGrid都对应⼀个数据模型,这样做的好处就是操作数据模型就相当于操作DataGrid表格了,但是这样做有⼀个缺陷,如果数据模型增加到⼀定的数量,⽐如⼏千个,这样你就需要在前台声明⼏千个表格,后台代码也需要有对应⼏千个数据模型,再进⼀步,表格的内容如果⽆法确定是动态加载的,这样的⽅法就不具备任何可⾏性了解决问题的思路:实现这个的思路其实⾮常淳朴简单,使⽤dynamic动态类型,在运⾏时动态的加载表格的ViewModel层。这样⼀来,我们就可以在运⾏时为某⼀个DataGrid动态的⽣成与其对应的类型了。具体Dynamic类型在此就不展开说了,可参见执⾏步骤:1、声明⼀个动态类型的VM层这个VM层中保存了所有⽣成⼀个类型的数据,包括:Properties:属性名称和属性类型的对应关系key:类型中属性的名字value:类型中属性的类型的实例colName_Property:列名和属性名的对应关系key:DataGrid表的列名称value:Property的属性名称AddProperty:动态⽅法,⽤于动态给Properties和ColName_Property添加对应关系public class DyDataDridModel : DynamicObject{ //
⽤来保存这个动态类型的所有属性; // string为属性的名字; // object为属性的值(同时也包含了类型); Dictionary
⽤来保存中⽂列名与属性的对应关系; Dictionary
为动态类型动态添加成员; public override bool TrySetMember(SetMemberBinder binder, object value) { if (!ns()) { (, value); } return true; } //
为动态类型动态添加⽅法; public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { //
可以通过调⽤⽅法的⼿段添加属性; if ( == "AddProperty" && ntCount == 3) { string name = args[0] as string; if (name == null) { //throw new ArgumentException("name");
result = null; return false; } //
向属性列表添加属性及其值; object value = args[1]; (name, value);
//
添加列名与属性列表的映射关系; string column_name = args[2] as string; ColName_(column_name, name); result = value; return true; } if( == "JudgePropertyName_StartEditing" && ntCount == 1) { string columnname = args[0] as string; if(columnname == null) { result = null; return false; }
//
在当前列名于属性列表中查找,看是否有匹配项; //
在当前列名于属性列表中查找,看是否有匹配项; if(ColName_nsKey(columnname)) { string key = ColName_Property[columnname]; if(nsKey(key)) { object property = Properties[key]; } } else { }
} return okeMember(binder, args, out result); } //
获取属性; public override bool TryGetMember(GetMemberBinder binder, out object result) { return Value(, out result); }}2、在前端声明⼀个没有任何列定义的DataGrid表格:
⽀持动态添加内容的类型dynamic model = new DyDataDridModel();//
向单元格内添加内容,这⾥是添加了⼀整⾏内容;perty("property2", new GridCell() { name = "343" }, "列2");perty("property0", new GridCell() { name = "123" }, "列0");perty("property1", new GridCell() { name = "321" }, "列1");(model);//
定义每⼀列显⽰的内容以及Binding的对象for (int i = 0; i <= 2; i++){ DataGridTextColumn column = new DataGridTextColumn(); = "列" + i; g = new Binding("property" + i + ".name"); aGrid_(column);}aGrid_ource = list;把上边的语句代码翻译回⽅式⼀或⽅式⼆的模式,是这个样⼦的:// VM层模型class VModel{ public GridCell property2; public GridCell property0; public GridCell property1;}//
数据模型public class GridCell{ public string name { get; set; } public void EditingCalback() { }}
逻辑层:ObservableCollection
= "343", = "123", = "321"});ntext = list;动态加载表的最终效果如下:以上,就是⽬前所有我对WPF的DataGrid控件使⽤的归纳,总结下来,需要掌握的知识点并不难。如果想要对DataGrid进⾏灵活应⽤的话,需要对MVVM架构有⼀个⼤致的认识,并且对动态类型有⼀定的了解,熟悉Python的同学,对动态类型认识起来,肯定就轻松很多了。本⽂有关DataGrid的内容都在WPF项⽬当中
发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689723156a281181.html
评论列表(0条)