初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
源码指引:github源码指引_初级代码游戏的博客-CSDN博客
C#是我多年以来的业余爱好,新搞的东西能用C#的就用C#了。
承接上一篇:WinUI3入门1:使用DataGrid控件显示表格-CSDN博客。
上一篇我们已经显示了表格,但是只显示一般是不够的,我们还要考虑动态修改。本篇我们解决对数据源的修改如何反映到DataGrid控件的问题。
说起来“修改”是一个问题,但是分解开是两个完全不同的问题:
- 添加和删除如何反应到界面
- 修改字段如何反映到界面
因为容器的“修改”是添加和删除,而字段的修改属于容器里的每个对象,技术上是完全不同的。
一、添加和删除如何反映到界面
DataGrid通过ItemSource绑定到数据源,数据源要求是个IEnumerable,通常用List<>,然而,List<>并没有变化通知的功能,因此我们之前用List<>无论如何都不能实现数据源添加修改反映到界面。
为了让DataGrid能够得到数据源变化通知,需要使用另一个模板:ObservableCollection<>。简单替换之后数据源的增加和删除就能立即反映到界面上了。
通过点击按钮给数据源增加数据:
Data tmp = new Data("aa", "", "", "");datas.Add(tmp);datas[0].Dir = datas.Count.ToString();注意此句尚不会更新到界面datas[0].File = datas.Count.ToString();注意此句尚不会更新到界面
效果如下:
注意,修改字段是不会反映上去的,即使隐藏控件然后再显示也不行。但是如果数据很多发生了滚动,一条数据重新出现时会显示为更新后的数据。(注:上图是已经添加了字段变化通知的效果,第一行第一列第二列已经被修改)
二、修改界面如何反应到字段
2.1 INotifyPropertyChanged
能够通知字段变化的数据类型必须支持INotifyPropertyChanged接口。该接口包含一个事件:
event PropertyChangedEventHandler PropertyChanged;
此事件在属性更改时发生。实现此接口的数据类型需要在每个属性更改是触发此事件。
2.2 实现INotifyPropertyChanged
实现过程相当繁琐,C#在引入无数令人困惑的语法甜点之后,为什么不给加个关键字指示一下呢?
以下是新的Data类的代码:
public class Data : INotifyPropertyChanged{String _dir;String _file;public String Dir { get { return _dir; } set { _dir = value; OnPropertyChanged(); } }public String File { get { return _file; } set { _file = value; OnPropertyChanged(); } }public String Ext { get; set; } = "";public String Type { get; set; } = "";public String Encode { get; set; } = "";public String BOM { get; set; } = "";public int CR { get; set; } = 0;public int CRLF { get; set; } = 0;public int LF { get; set; } = 0;public String State { get; set; } = "";public event PropertyChangedEventHandler PropertyChanged = delegate { };public void OnPropertyChanged([CallerMemberName] string propertyName=""){// Raise the PropertyChanged event, passing the name of the property whose value has changed.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}public Data(String str, String n,String str2, String b){this.Dir = str;this.Ext = n;this.File = str2;this.State = b;}public static ObservableCollection<Data> Datas(){return new ObservableCollection<Data>(new Data[4] {new Data("a", "1","aaa","false"),new Data("b","2","bbb","false"),new Data("c", "3","ccc","true"),new Data("d", "4","ddd","true")});}}
定义INotifyPropertyChanged要求的事件:
public event PropertyChangedEventHandler PropertyChanged = delegate { };
实现辅助的触发时间函数,以简化每个属性的代码:
public void OnPropertyChanged([CallerMemberName] string propertyName=""){// Raise the PropertyChanged event, passing the name of the property whose value has changed.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}
一个属性的实现:
String _dir;public String Dir { get { return _dir; } set { _dir = value; OnPropertyChanged(); } }
我们还记得原来的写法很简单:
public String Dir { get; set; } = "";
为什么复杂了这么多?
- 因为要调用函数触发事件,set必须写出来
- 因为set必须写出来,就必须先给自己赋值
- 在set里给自己赋值会触发set,无限递归
- 所以不能使用简化属性语法,必须额外定义一个实际变量
- 因此get也必须写出来
对每一个需要实时更新界面的属性都要这样写。
三、xaml设置和代码设置
xaml可以设置Mode为单项或双向,代码设置ItemSource时没有设置的地方,目前看至少是OneWay方式,是否支持双向,我们以后再研究。
(这里是文档结束)