關於ObservableCollection的更新與不更新分析

cbaa發表於2023-05-06

因為最近在WPF專案中,遇到ObservableCollection這個屬性的頻繁使用,一個一個坑跳過來,今天看到這個貼子

玩轉INotifyPropertyChanged和ObservableCollection - 包建強 - 部落格園 (cnblogs.com)

其中分析很透徹了,但是留了一點遺憾,而且在其中引起了一個想法,做一個專案來測試一下。

我們知道在Binding一個item的時候,想要其中屬性變化時,UI同步變化,需要實現OnPropertyChanged介面,我因為習慣於mvvm.Toolkit,也就是說需要繼承ObservableObject,

類似這樣:

 public class Student:ObservableObject
    {
        private string name;
        public string Name
        {
            get => name;
            set => SetProperty(ref name, value);
        }
        private int age;
        public int Age
        {
            get => age;
            set=>SetProperty(ref age, value);
        }
}

在Binding到集合項的時候,通常需要這樣

pulic  ObservableCollection<Student> Students_t = new ();

透過上面2條,可以實現:集合中增加、刪除元素,及元素屬性更新的時候,UI可自動更新。

但是,但是的但是,如果需要重新整理資料的時候,比如說,人工清除當前集合,重新從源頭讀取,通常這樣:

Students=new ObservableCollection<Student>(ctx.students)

這就壞了,發現UI沒更新。原因在於,ObservableCollection只關注內部的元素變化,但當他自己發生了變化,其實對集合Binding關係已經破壞了,因為這是一個新建的集合,等於更新了Students這個物件,而不是對這個物件的內部元素作出的增刪。

希望我說得明白了。

如果我說明白了,就是說,前面我們忽略了一個問題。

Students仍然不是可觀察物件。

所以,要修改為

 private ObservableCollection<Student> students_c = new ();
public ObservableCollection<Student> Student_c
        {
            get => students_c;
            set => SetProperty(ref students_c, value);
        }
}

開始我說的忽發奇想是,如果我對List<T>實現可觀察,是否能夠代替了ObservableCollection?測試結果是,是的,在重置資料的時候,確實是可以實現的(很奇怪嗎?),但是在增刪元素的時候,仍然不行,仍然需要ObservableCollection。

對以上各種情況,我做的測試專案,見:

https://gitee.com/ppcba/observable-collection-demo.git

如果有同樣疑惑的,建議參考著自己做一下,不然會仍然糊塗著。

==========2023-5-7補充=========

ObservableCollection的重置還有一種場景,就是自身不帶AddRange方法,只好更新它後面的資料來源,習慣上是這樣使用的:

StuList.AddRange(stus);
Students=New ObservableCollection<Student>(StuList);

這就使得ObservableCollection被重置了。

所以,我現在專案上,仍然把ObservableCollection作為欄位,而不是屬性,需要重置的時候,就清空,然後使用擴充套件方法AddRange方法。

但從MVVM強迫症的角度,還是一切OnPropertyChanged進行到底為好。

相關文章