ObservableCollection <t>和OnCollectionChanged </t>

时间:2010-08-26 15:41:23

标签: c# wpf

我正在学习WPF中的ObservableCollections,我不清楚。我知道如果我将控件绑定到ObservableCollection并且集合发生更改,则控件将反映更改。我的问题是:

  • ObservableCollection实现了INotifyCollectionChanged,它只是一个事件CollectionChanged。每当集合发生变化但是谁订阅了该事件时,应该触发该事件?它是否在您创建对集合的绑定时自动完成?

  • 我正在使用Reflector查看ObservableCollection,并试图查看何时触发CollectionChanged事件。但是我无法找到它的位置。例如,当我向集合添加新项目时,我想查看它何时被触发。 Add(...)在ObservableCollection的基类Collection中实现,但Collection没有实现INotifyCollectionChanged,所以我不明白如何通知绑定控件更改。

我猜这很多内容都是在幕后处理的,但我们非常感谢任何信息。

5 个答案:

答案 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提供INotifyCollectionChangedObservableCollection<T>的“肉和土豆”所在的位置。但是,要回答您的第一个问题,请阅读WPF and Binding Sources

基本上,当你在WPF中绑定一个对象时,会根据某些“契约”检查它,其中一个是INotifyCollectionChanged。 WPF处理附加到事件和接收通知。 Control然后确定在通知其DependencyProperty个对象的更新时如何响应。

有趣的是,WPF在绑定中使用集合视图而不是集合本身:

  

WPF永远不会直接绑定到集合。如果将集合指定为绑定源,则WPF实际上绑定到集合的默认视图。有关默认视图的信息,请参阅Data Binding Overview