初級代碼游戲的專欄介紹與文章目錄-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方式,是否支持雙向,我們以后再研究。
(這里是文檔結束)