List和ObservableCollection和ListBinding在MVVM模式下的對比
List
當對List進行增刪操作后,并不會對View進行通知。
//Employee
public class Employee : INotifyPropertyChanged
{public event PropertyChangedEventHandler? PropertyChanged;public string Name { get; set; }private int salary;public int Salary{get { return salary; }set{salary = value;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Salary)));}}
}
<!--View-->
<Grid><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="40" /></Grid.RowDefinitions><DataGrid ItemsSource="{Binding Employees}" /><StackPanelGrid.Row="1"VerticalAlignment="Center"Orientation="Horizontal"><Button Command="{Binding addCommand}" Content="Add" /><TextBlock Text="工資總額" /><TextBox Text="{Binding TotalSalary, Mode=OneWay}" /></StackPanel>
</Grid>
//MainViewModel
public partial class MainViewModel:INotifyPropertyChanged
{public List<Employee> Employees { get; }public int TotalSalary=>Employees.Sum(x => x.Salary);public MainViewModel(){Employees = new List<Employee>() { new Employee(){Name="Tom",Salary=200},new Employee(){Name="Tim",Salary=450},new Employee(){Name="Jerry",Salary=780},new Employee(){Name="Jake",Salary=540},new Employee(){Name="Kit",Salary=670},};}[RelayCommand]private void add(){Employees.Add(new Employee() { Name = "Lit", Salary = 260 });//通知TotalSalayPropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(TotalSalary)));}public event PropertyChangedEventHandler? PropertyChanged;
}
可以看到,點擊Add后,上面列表中并沒有更新,但是工資總額已經更新,這說明新的數據已經加到了List中,但是List并沒有通知View。
ObservableCollection
-
ObservableCollection
可以在增加和刪除時,對View進行通知修改MainViewModel
public partial class MainViewModel:INotifyPropertyChanged {public ObservableCollection<Employee> Employees { get; }public int TotalSalary=>Employees.Sum(x => x.Salary);public MainViewModel(){Employees = new ObservableCollection<Employee>() { new Employee(){Name="Tom",Salary=200},new Employee(){Name="Tim",Salary=450},new Employee(){Name="Jerry",Salary=780},new Employee(){Name="Jake",Salary=540},new Employee(){Name="Kit",Salary=670},};}[RelayCommand]private void add(){Employees.Add(new Employee() { Name = "Lit", Salary = 260 });PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(TotalSalary)));}//增加一個Modify方法[RelayCommand]private void Modify(){Employees[2].Salary = 999;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TotalSalary)));}public event PropertyChangedEventHandler? PropertyChanged; }
可以發現,點擊Add,View中也相應地進行了更新,而且工資總額也相應改變。同時,無論是add還是Modify,都使用了
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TotalSalary)));
它的改進做法是使用CollectionChanged
事件。
//改進做法,增加CollectionChanged,可以刪除add()和Modify()的PropertyChanged...了
Employees.CollectionChanged += (_, _) => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TotalSalary))); };
BindingList
BindingList提供了更多的功能,提供了排序、搜索、過濾等功能。此外,BindingList 還提供了對數據源的更多控制,如 AllowNew、AllowEdit 和 AllowRemove 屬性,用于控制是否允許添加、編輯和刪除項。
BindingList提供了ListChanged事件,該事件參數中提供了詳細的信息,但是ObservableCollection 是線程安全的,可以在多個線程中使用。而 BindingList 不是線程安全的,如果需要在多個線程中使用,需要進行額外的線程同步處理。