一、ObservableCollection是什么,为什么要使用它
是什么:
一个泛型用来通知的集合,源码定义如下:
为什么用:
WPF是数据驱动界面,当后台数据变更时触发通知而更新界面,常规代码如下:
public event PropertyChangedEventHandler? PropertyChanged;
private int _id;
public int Id
{
get => _id;
set
{
_id = value;
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(nameof(Id)));
}
}
这样写时后台变更Id,界面显示可以正常刷新。
但当我们使用集合时,问题就出现了,集合的添加、移除是不会触发set的,也就是说,我们后台添加集合时,不会发送通知,界面也就不会刷新,前台后台数据就不一致了。
此时ObservableCollection出现了,微软官方包装了Collection<T>,给集合添加、移除方法内置了通知,此时,我们将需要展示在界面上的的数据集合定义为ObservableCollection就可以解决绝大数问题,代码如下:
private ObservableCollection<int> _collection;
public ObservableCollection<int> Collection {
get => _collection;
set
{
_collection= value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Collection)));
}
}
二、ObservableCollection的坑
本来我一直用的舒舒服服,直到某一天遇到了Multibinding,先看如下Xaml代码:
<ListBox ItemsSource="{Binding Collection}" />
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{x:Static converters:MultiConverter.Instance}">
<Binding Path="Collection" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
上面一个ListBox的ItemSource和下面一个TextBlock的Text都绑定之前定义的集合Collection,唯一不同的就是上面是普通binding,下面是Multibinding。
当后台给Collection添加数据时,ListBox可以正常更新,TextBlock却一直不会更新、不会进Converter。
经过一个下午的调试和搜索,终于在StackoverFlow上找到了线索:
然后我翻看ObsevableCollection的源码
结果已经一目了然了,从源码看出,集合增删改查时会触发两个PropertyChanged(Count和Indexer)和一个CollectionChanged。
而Multibinding不接收CollectionChanged的通知,只接收PropertyChanged,但集合的增删改查并不会触发定义的集合这个属性的PropertyChanged,故如此绑定的界面并不会刷新。
如何解决:
两个解决办法:
1、在Multibinding里加一个集合数量的绑定,这样就能收到OnCountPropertyChanged()此方法的通知从而触发进Converter处理数据,代码如下:
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{x:Static converters:MultiConverter.Instance}">
<Binding Path="Collection" />
<Binding Path="Collection.Count" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
2、在ObservableCollection上面再封装一层添加引发集合的PropertyChanged逻辑。
相关链接:https://stackoverflow.com/questions/5583830/multibinding-with-multivalueconverter-does-not-update