我正在学习WPF中的ObservableCollections,我不清楚。我知道如果我将控件绑定到ObservableCollection并且集合发生更改,则控件将反映更改。我的问题是:
ObservableCollection实现了INotifyCollectionChanged,它只是一个事件CollectionChanged。每当集合发生变化但是谁订阅了该事件时,应该触发该事件?它是否在您创建对集合的绑定时自动完成?
我正在使用Reflector查看ObservableCollection,并试图查看何时触发CollectionChanged事件。但是我无法找到它的位置。例如,当我向集合添加新项目时,我想查看它何时被触发。 Add(...)在ObservableCollection的基类Collection中实现,但Collection没有实现INotifyCollectionChanged,所以我不明白如何通知绑定控件更改。
我猜这很多内容都是在幕后处理的,但我们非常感谢任何信息。
答案 0 :(得分:3)
回答你的第一个问题:它全部从ItemContainerGenerator类的“Items”属性开始(所有ItemsControl对象都有一个实例)。如果查看所述“Items”属性的setter,你会发现它有特殊的逻辑来检查给定的IList是否为INotifyCollectionChanged类型,它将附加一个事件监听器。
ItemContainerGenerator.Items属性:
internal IList Items
{
get
{
return this._items;
}
set
{
if (this._items != value)
{
INotifyCollectionChanged source = this._items as INotifyCollectionChanged;
if ((this._items != this.Host.View) && (source != null))
{
CollectionChangedEventManager.RemoveListener(source, this);
}
this._items = value;
source = this._items as INotifyCollectionChanged;
if ((this._items != this.Host.View) && (source != null))
{
CollectionChangedEventManager.AddListener(source, this);
}
}
}
}
它与Bindings无关。请参阅,如果您有以下代码根本不使用Bindings,则集合更改通知仍然有效:
<Window x:Class="DynamicObjectTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<Button Click="Button_Click">click</Button>
<ListBox x:Name="listBox"/>
</StackPanel>
</Grid>
</Window>
public partial class MainWindow : Window
{
ObservableCollection items = new ObservableCollection();
public MainWindow()
{
InitializeComponent();
this.listBox.ItemsSource = items;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
items.Add("A");
}
}
答案 1 :(得分:1)
简单明白的答案:
ObservableCollections更新控件,当从集合中添加或删除对象时,它们将被数据绑定。
当修改集合中的对象时,它们不会更新数据绑定。
答案 2 :(得分:1)
每当集合发生变化但是谁订阅了该事件时,应该触发该事件?它是否在您创建对集合的绑定时自动完成?
Binding
对象订阅了来源的CollectionChanged
和/或PropertyChanged
个事件。
答案 3 :(得分:0)
从反映.Net 3.5,Collection&lt; T&gt;的Add()方法调用InsertItem:
public void Add(T item)
{
//...
int count = this.items.Count;
this.InsertItem(count, item);
}
在ObservableColletion&lt; T&gt;中重写了InsertItem(),它会通知:
protected override void InsertItem(int index, T item)
{
this.CheckReentrancy();
base.InsertItem(index, item);
this.OnPropertyChanged("Count");
this.OnPropertyChanged("Item[]");
this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
}
答案 4 :(得分:0)
@Grant Crofton's answer提供INotifyCollectionChanged
内ObservableCollection<T>
的“肉和土豆”所在的位置。但是,要回答您的第一个问题,请阅读WPF and Binding Sources。
基本上,当你在WPF中绑定一个对象时,会根据某些“契约”检查它,其中一个是INotifyCollectionChanged
。 WPF处理附加到事件和接收通知。 Control
然后确定在通知其DependencyProperty
个对象的更新时如何响应。
有趣的是,WPF在绑定中使用集合视图而不是集合本身:
WPF永远不会直接绑定到集合。如果将集合指定为绑定源,则WPF实际上绑定到集合的默认视图。有关默认视图的信息,请参阅Data Binding Overview。