Flack
Flack

Reputation: 5899

ObservableCollection<T> and OnCollectionChanged

I was learning about ObservableCollections in WPF and something is not clear to me. I understand that if I bind a control to an ObservableCollection and the collection changes, the control will reflect the changes. My questions are:

I am guessing that a lot of this is taken care of under the covers but any info is greatly appreciated.

Upvotes: 1

Views: 2972

Answers (5)

ASanch
ASanch

Reputation: 10373

To answer your first question: it all starts inside the "Items" property of the ItemContainerGenerator class (which, all ItemsControl objects have an instance of). If you look at the setter for the said "Items" property, you'll see that it has special logic that checks if the given IList is of type INotifyCollectionChanged, it will attach an event listener.

ItemContainerGenerator.Items property:


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);
            }
        }
    }
}

It really has nothing to do with Bindings. See, if you have the following code that doesn't use Bindings at all, the collection changed notification will still work:

<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");
        }
    }

Upvotes: 3

Robert Rossney
Robert Rossney

Reputation: 96722

That event should be fired whenever the collection changes but who subscribes to that event? Is it done automatically when you create a binding to the collection?

The Binding object subscribes to the source's CollectionChanged and/or PropertyChanged events.

Upvotes: 1

user7116
user7116

Reputation: 64068

@Grant Crofton's answer provides where the "meat and potatoes" of INotifyCollectionChanged is inside of ObservableCollection<T>. However, to answer your first question you should read up on WPF and Binding Sources.

Basically, when you bind an object in WPF, it is checked against certain "contracts", one of which is INotifyCollectionChanged. WPF handles attaching to the event and receiving the notifications. The Control then determines how to respond when it is notified of an update to one of its DependencyProperty objects.

Interestingly enough, WPF uses a View of a Collection rather than the collection itself in a binding:

WPF never binds directly to a collection. If you specify a collection as a binding source, WPF actually binds to the collection's default view. For information about default views, see Data Binding Overview.

Upvotes: 0

Grant Crofton
Grant Crofton

Reputation: 9101

From reflecting .Net 3.5, Collection<T>'s Add() method calls InsertItem:

public void Add(T item)
{
    //...
    int count = this.items.Count;
    this.InsertItem(count, item);
}

InsertItem() is overridden in ObservableColletion<T>, which does the notifying:

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);
}

Upvotes: 0

Scrappydog
Scrappydog

Reputation: 2874

Simple plain english answer:

ObservableCollections update controls they are databound to when objects are added or removed from the collections.

They do NOT update databinding when objects in the collection are modified.

Upvotes: 1

Related Questions