Tuesday, August 4, 2009

Binding to an ObservableCollection in a WPF ListBox

There's a really crucial, and when one stops to consider it, totally obvious step to take when binding an ObservableCollection to a WPF items container... make sure the collection exists!

I spent a fruitless couple of hours recently staring at blog after blog after documentation after blog on this, because I got the timing of the interactions wrong.

There's heaps of documentation available that explains how your View code (your xaml) will listen to changes in ObservableCollections (i.e. items are added or removed from the collection), and how it will listen for changes to objects that implement the INotifyPropertyChanged interface (and fire PropertyChanged as appropriate).

However - the bit I was missing was the fact that the View binds to the ViewModel very early on in the piece; if the ObservableCollection is still null, then the Binding object is null... creating new objects later is irrelevant, because the view is not listening to those new objects, it is listening to 'null'. We need to instantiate an instance of the collection (even if it is empty) in the ViewModel's constructor, such that the binding has an object against which it can listen for changes.

The wrong way:
- declare private instance of ObservableCollection, and public getter that returns this instance
- Bind to Property (which is still null)
- Do work to get data (triggered by some Command, like button click)
- set ObservableCollection to be new instance and populate with data.
- Wonder why no changes are propagating to the UI


The right way:
- Instantiate private ObservableCollection in *Constructor* for ViewModel
- Bind to it (empty *but non-null* collection)
- Do work to get data (triggered by some Command, like button click)
- populate (already instantiated and bound) Collection with data
- Bask in glory as UI fills with data goodness


This is so obvious when you think about it...

6 comments:

  1. Ian,

    It's things like this which which folk new to WPF (raises hand) scratch their heads over for a whole lot more than a couple of hours, unfortunately. Thanks for stating it explicitly. It all helps to clarify and get control over this lovely-dovely new tech.

    Best of British to ya!

    Gregg Cleland
    (Chch NZ)

    ReplyDelete
  2. Thanks Gregg - it's an awesome platform, eh? I just love it :)

    ReplyDelete
  3. This was really helpful ... Thanks Ian

    ReplyDelete
  4. Over 8 hours pouring over boards to find this gem. Thank you! Problem solved. Yahoo!

    ReplyDelete
  5. I am extremely lucky to have found this after chasing this rabbit all weekend. I kept trying to it XAML markup to no avail by setting the DataContext of the main window to my public class containing the property I was using to bind to my progress bar value property. I declared my class instance name in the body of the window class and newed it up in the window ctor and viola!
    Thank you -- Thank you -- Thank you!!!!

    ReplyDelete