List和ObservableCollection和ListBinding在MVVM模式下的对比

List和ObservableCollection和ListBinding在MVVM模式下的对比

List和ObservableCollection和ListBinding在MVVM模式下的对比

List

当对List进行增删操作后,并不会对View进行通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//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)));
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--View-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Employees}" />
<StackPanel
Grid.Row="1"
VerticalAlignment="Center"
Orientation="Horizontal">
<Button Command="{Binding addCommand}" Content="Add" />
<TextBlock Text="工资总额" />
<TextBox Text="{Binding TotalSalary, Mode=OneWay}" />
</StackPanel>
</Grid>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//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 });
//通知TotalSalay
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(TotalSalary)));
}

public event PropertyChangedEventHandler? PropertyChanged;
}

可以看到,点击Add后,上面列表中并没有更新,但是工资总额已经更新,这说明新的数据已经加到了List中,但是List并没有通知View。

ObservableCollection

  • ObservableCollection可以在增加和删除时,对View进行通知

    修改MainViewModel

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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事件。

1
2
//改进做法,增加CollectionChanged,可以删除add()和Modify()的PropertyChanged...了
Employees.CollectionChanged += (_, _) => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TotalSalary))); };

BindingList

BindingList提供了更多的功能,提供了排序、搜索、过滤等功能。此外,BindingList 还提供了对数据源的更多控制,如 AllowNew、AllowEdit 和 AllowRemove 属性,用于控制是否允许添加、编辑和删除项。

BindingList提供了ListChanged事件,该事件参数中提供了详细的信息,但是ObservableCollection 是线程安全的,可以在多个线程中使用。而 BindingList 不是线程安全的,如果需要在多个线程中使用,需要进行额外的线程同步处理。

List和ObservableCollection和ListBinding在MVVM模式下的对比

https://bubuweiying.site/List和ObservableCollection和ListBinding在MVVM模式下的对比/

作者

步步为营

发布于

2024-05-08

更新于

2025-03-15

许可协议