views:

298

answers:

4

I am new to WPF and trying to wrap my head around WPF's framework, what it does and does not do for you.

To clarify this, I would like to know what is the difference between this:

public List<MyCustomObject> MyCustomObjects
{
    get { return (List<MyCustomObject>)GetValue(MyCustomObjectsProperty); }
    set { SetValue(MyCustomObjectsProperty, value); }
}

public static readonly DependencyProperty MyCustomObjectsProperty =
    DependencyProperty.Register("MyCustomObjects", typeof(List<MyCustomObject>),
    typeof(Main), new UIPropertyMetadata(new List<MyCustomObject>()));



and this:

public ObservableCollection<MyCustomObject> MyCustomObjects { get; set; }

public Main ()
{
    MyCustomObjects = new ObservableCollection<<MyCustomObject>();
}
+2  A: 

In the first case, you're setting up a Dependency Property containing a List<T> instance.

In the second, you're making a normal CLR property, but having it setup as an ObservableCollection<T>.

For WPF Data Binding, there are some differences here.

Typically, you want all of your properties in the DataContext (which is the object that, by default, things "bind" to) to either implement INotifyPropertyChanged or to be a Dependency Property. This lets the binding framework know when changes are made to that object. Normally, though, you'd only use a Dependency Property if your working with a custom control - it's usually a better idea to have your object to which your data bound be a separate class, assigned to the DataContext. (For details here, see Josh Smith on MVVM or my recent detailed post on MVVM...)

However, with a collection, you typically also want the binding system to know when the items within the collection change (ie: an item is added). ObservableCollection<T> handles this by implementing INotifyCollectionChanged.

By using the second approach (using an ObservableCollection<T>), your UI can tell when items were added or removed from the collection - not just when a new collection is assigned. This lets things work automatically, like a ListBox adding elements when a new item is added to your collection.

Reed Copsey
+4  A: 

Ok, we must put some order into things, there's a few concepts mixed in together here.

First of all, you're asking what the difference is between a field-backed property and a dependency property. Google would be your best friend, however I recommend this blog post by WPF's vanguard Josh Smith: Overview of dependency properties in WPF

In short: dependency properties support the richness that is WPF: Styling, animation, binding, metadata, and more.

Secondly, you're asking what the difference is between a List and an ObservableCollection. Well the latter provides change notifications (in the forms of events) on any change to the collection (addition, removal, change of order, clearing, etc.), and the former does not. You can read more about that here: The ObservableCollection Class

In short: ObservableCollection provides change notifications which are required for the UI to automatically reflect changes in the view model.

Aviad P.
+1  A: 

1:

You're using a dependency property to "tell" the framework when that property is changed. This will have the following consequences for your binding:

MyCustomObjects.Add(new MyCustomObject()); //Wont update the view through databinding
MyCustomObjects = new List<MyCustomObject>(); //Will update the view through databinding

You could gain the same databinding functionality by implementing INotifyPropertyChanged on which ever class exposes the property, but dependency properties a capable of much more than just notifying about changes. These are rather advanced features though, which you aren't likely to come across in your average joe app :)

2:

You're using an observable collection, which implements INotifyCollectionChanged for you, to tell the databinding whenever the content of the collection has changed. This will have the opposite consequences than #1:

MyCustomObjects.Add(new MyCustomObject()); //Will update the view through databinding
MyCustomObjects = new ObservableCollection<MyCustomObject>(); //Won't update the view through databinding
cwap
If I do an ObserverableCollection that is a DependencyProperty will I get both? Is that a good idea?
Vaccano
You'll get both, yes. If it's a good idea depends on your needs, but I've often implemented it (though I prefer to use INotifyPropertyChanged instead, as it's simpler).
cwap
Since the OP approved the answer, I'm taking the liberty to edit it to correct some inaccuracies (INotifyPropertyChanged -> INotifyCollectionChanged, etc.)
Aviad P.
Looks good Aviad. Sry about the incorrectness. Was typing too fast as usual :)
cwap
+3  A: 

In addition to Aviad and Reed's answers, I would like to point out a serious bug in your first code sample :

public static readonly DependencyProperty MyCustomObjectsProperty =
    DependencyProperty.Register("MyCustomObjects", typeof(List<MyCustomObject>),
    typeof(Main), new UIPropertyMetadata(new List<MyCustomObject>()));

The new List<MyCustomObject>() used as the default value will be created only once, so by default all instances of your type will share the same List<MyCustomObject> instance, which is probably not what you want... The only sensible default value here is null

Thomas Levesque
So true, and a common newbie mistake. Watch out for this!
Aviad P.
Hmmm, I am afraid I don't get this... I want one MyCustomObjects list. I am not making more than one instance of the MyCustomObjects variable (you make reference to "all instances" but would I not just have one instance as declared in my property). I hope you reply because I can tell this is important, but I am just not getting it.
Vaccano
The same instance of the list will be shared by all your `Main` type objects (unless explicitly assigned otherwise).
Aviad P.
Ah.. I think I get it. I have not hit problems because Main is a single instance class for me. If I had more than one instance of Main then they would all share the same instance of the "list". I can see how this could cause nasty hard to find problems. Thanks for the tip Thomas and Avaid.
Vaccano