我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
源码指引:github源码指引_初级代码游戏的博客-CSDN博客
C#是我多年以来的业余爱好,新搞的东西能用C#的就用C#了。
承接上一篇:WinUI3入门1:使用DataGrid控件显示表格-CSDN博客。
上一篇我们已经显示了表格,但是只显示一般是不够的,我们还要考虑动态修改。本篇我们解决对数据源的修改如何反映到DataGrid控件的问题。
说起来"修改"是一个问题,但是分解开是两个完全不同的问题:
- 添加和删除如何反应到界面
- 修改字段如何反映到界面
因为容器的"修改"是添加和删除,而字段的修改属于容器里的每个对象,技术上是完全不同的。
一、添加和删除如何反映到界面
DataGrid通过ItemSource绑定到数据源,数据源要求是个IEnumerable,通常用List<>,然而,List<>并没有变化通知的功能,因此我们之前用List<>无论如何都不能实现数据源添加修改反映到界面。
为了让DataGrid能够得到数据源变化通知,需要使用另一个模板:ObservableCollection<>。简单替换之后数据源的增加和删除就能立即反映到界面上了。
通过点击按钮给数据源增加数据:
cs
Data tmp = new Data("aa", "", "", "");
datas.Add(tmp);
datas[0].Dir = datas.Count.ToString();注意此句尚不会更新到界面
datas[0].File = datas.Count.ToString();注意此句尚不会更新到界面
效果如下:

注意,修改字段是不会反映上去的,即使隐藏控件然后再显示也不行。但是如果数据很多发生了滚动,一条数据重新出现时会显示为更新后的数据。(注:上图是已经添加了字段变化通知的效果,第一行第一列第二列已经被修改)
二、修改界面如何反应到字段
2.1 INotifyPropertyChanged
能够通知字段变化的数据类型必须支持INotifyPropertyChanged接口。该接口包含一个事件:
cs
event PropertyChangedEventHandler PropertyChanged;
此事件在属性更改时发生。实现此接口的数据类型需要在每个属性更改是触发此事件。
2.2 实现INotifyPropertyChanged
实现过程相当繁琐,C#在引入无数令人困惑的语法甜点之后,为什么不给加个关键字指示一下呢?
以下是新的Data类的代码:
cs
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要求的事件:
cs
public event PropertyChangedEventHandler PropertyChanged = delegate { };
实现辅助的触发时间函数,以简化每个属性的代码:
cs
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));
}
一个属性的实现:
cs
String _dir;
public String Dir { get { return _dir; } set { _dir = value; OnPropertyChanged(); } }
我们还记得原来的写法很简单:
cs
public String Dir { get; set; } = "";
为什么复杂了这么多?
- 因为要调用函数触发事件,set必须写出来
- 因为set必须写出来,就必须先给自己赋值
- 在set里给自己赋值会触发set,无限递归
- 所以不能使用简化属性语法,必须额外定义一个实际变量
- 因此get也必须写出来
对每一个需要实时更新界面的属性都要这样写。
三、xaml设置和代码设置
xaml可以设置Mode为单项或双向,代码设置ItemSource时没有设置的地方,目前看至少是OneWay方式,是否支持双向,我们以后再研究。
(这里是文档结束)