2

I was curious to know the differences and/or benefits between these two class options. I've seen several examples of view models here on stack overflow and both of the class examples below are often seen. I'm not sure what the differences are. Hope someone can explain why? and when to use one over the other?... Thank you.

Class Option #1

private ObservableCollection<Family> families;

public ObservableCollection<Family> Families
{
    get { return families ?? (families = new ObservableCollection<Families>()); }
}  

Class Option #2

private ObservableCollection<Family> families; 

public ObservableCollection<Family> Families
{
    get { return families; }
    set
    {
        families = value;
        NotifyPropertyChanged("Families");
    }
}

should they be combined?

public ObservableCollection<Family> Families
{
    get { return families ?? (families = new ObservableCollection<Family>()); }
    set
    {
        families = value;
        NotifyPropertyChanged("Families");
    }
}
JokerMartini
  • 5,674
  • 9
  • 83
  • 193

2 Answers2

3

The first option:

private ObservableCollection<TabItem> families;

public ObservableCollection<TabItem> Families
{
    get { return families ?? (families = new ObservableCollection<Families>()); }
}  

is used when you need to lazily instantiate the backing field of a readonly property. Since there is no setter here, you can never assign a value to the property, you may only read the value.

This approach will let you create the backing field at the last possible instant, when you need it. If this is data-bound, then the lazy instantiation is wasted as the view will query for the property value during creation, meaning the backing field will always immediately be instanced.

The second option

private ObservableCollection<Family> families; 

public ObservableCollection<Family> Families
{
    get { return families; }
    set
    {
        families = value;
        NotifyPropertyChanged("Families");
    }
}

Allows both read and write to the property. Since the property can have a new value assigned to it, it must call NotifyPropertyChanged so that the View can be told the value has been changed. Once the view knows the value has changed, it will refresh itself by fetching the new value from the property.

In the scenario of databound properties, combining the two is really just a waste IMO. The view will databind to the property when the DataContext is assigned and instance the backing field.

For properties that are not databound, then the act of lazily instantiation is up to you. Will creating the collection require a lot of overhead? In the example you provided, no. However if you were to lazily create it from some other data-source, that could be a bit expensive, then yes.

It's really up to the problem you are trying to solve with the property.

Johnathon Sullinger
  • 7,097
  • 5
  • 37
  • 102
1

I'm not sure I fully understand the question, as to me the differences between the two options are self-evident. But taking the question at face-value:

Option #1 has two significant characteristics:

  1. It is read-only. This is not common, but of course can work in some situations.
  2. It is lazy. I.e. it does not initialize the underlying collection until accessed. IMHO this is of limited value in WPF view-model scenarios, because typically a property will be bound to something else, and so as soon as the object is instantiated, some other object is going to read the property and force initialization of the underlying collection anyway.

Option #2 is a typical implementation of INotifyPropertyChanged. This works with WPF's property binding system, but doesn't take full advantage of the system.

The differences are pretty obvious, I think: since the first option is read-only, it has no need for property-changed notification, and so of course does not implement that. On the other hand, the second option requires external initialization of the property; not only is it not lazy like the first, it doesn't even initialize the property at all, leaving the default value as null.

If you wanted a view-model with features of both (lazy initialization and writeability/INotifyPropertyChanged implementation), then yes…you could in fact combine techniques found in both examples.

Personally, I prefer to implement my view-model classes as DependencyObject subclasses whenever possible (which is nearly all the time). This requires a little bit more typing, because of the verbosity of declaring DependencyProperty objects, but it's fully integrated with the WPF binding system, can be more efficient and enables binding features not available when only using INotifyPropertyChanged (such as value coercion).

A DependencyObject property doesn't look anything like either of the two examples you posted. Instead, it might look something like this:

class ViewModel : DependencyObject
{
    public static readonly DependencyProperty FamiliesProperty =
        DependencyProperty.Register("Families", typeof(ObservableCollection<Families>),
        typeof(ViewModel), new PropertyMetadata(new ObservableCollection<Families>()));

    public ObservableCollection<Family> Families
    {
        get { return (ObservableCollection<Family>)GetValue(FamiliesProperty); }
        set { SetValue(FamiliesProperty, value); }
    }
}


So, when should you implement INotifyPropertyChanged, and when should you inherit DependencyObject instead. Frankly, I find this to come down to personal preference as much as anything else. It's unusual for the actual trade-offs to be relevant. But there are trade-offs.

One of the most thorough discussions can be found here:
INotifyPropertyChanged vs. DependencyProperty in ViewModel
For a full understanding, be sure to read the entire discussion, i.e. all answers, and not just the accepted one.

To briefly summarize some of the highlights:

  1. Advantages for using DependencyObject and DependencyProperty include:

    a. Being able to use the property as a target for binding. WPF can use INotifyPropertyChanged object properties as the source for binding, but target properties for binding must be dependency properties. For simple scenarios, this isn't an issue, but on occasion you may want to chain property bindings and/or declare the view-model in XAML with a source binding (even if only to initialize it), and only dependency properties will allow this.

    b. More efficient. The WPF binding system is optimized for the dependency property scenario, and updates to property values will happen more quickly when using dependency properties than when using INotifyPropertyChanged. Much of the time, this won't matter. Computers are fast, users are slow, and there's a lot of overhead in other areas of the API as compared to binding. But in some cases it can matter.

    c. Access to other features of the dependency property system, such as value coercion.
  2. Advantages for using INotifyPropertyChanged include:

    a. Not required to inherit a concrete type. In practice, most people wind up using a dedicated base class that implements the interface, and so this winds up a wash. In addition, if a view-model class inherits any other type, it's almost always going to be another view-model class that already inherits an appropriate base class (whether DependencyObject or a helper base class that implements INotifyPropertyChanged). But it's a theoretical possibility.

    b. You can more easily serialize the object, as DependencyObject is itself not serializable.

    c. Ability to override Equals() and GetHashCode(). Though in practice, this is likely something you don't want to do on a view-model anyway, as they are inherently mutable and so if you are relying on equality comparisons, you need to be very careful to not touch the view-model's values after you've used its equality features (e.g. stored the objects in a hash set or dictionary). In the event you do want to do equality comparisons, you also can just implement IEqualityComparer<T> for your view-model class, whether it's a DependencyObject or not.

    d. Its properties can be updated any thread (DependencyObject requires the object be accessed on the thread that owns it). Again, in practice this is not much of a concern, because the nature of a view-model is to be bound to some other object that also has thread affinity. I.e. if you mutate your view-model on some non-UI thread, it will lead to calling into an object that does require the UI thread and fail anyway. Conversely, the DependencyObject itself can still be used in non-UI threads…you just can't do anything with it that would affect a dependency property, or create in it other objects that require the UI thread (e.g. other dependency objects). On occasion, this limitation may matter but in most cases it won't.

In other words, all of the above are genuine practical differences between the two techniques, but in practice none of the presumed advantages for either technique is really all that important.

Community
  • 1
  • 1
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • The intent of a DependencyProperty is to extend functionality to a DependencyObject. You're mixing a view specific piece of functionality here with your view model. DependencyProperties also have a large amount of overhead than a standard INPC implementation. You've also removed the ability to now use any other base class across all of your view models. – Johnathon Sullinger Oct 17 '15 at 03:05
  • @JohnathonSullinger: IME, view-model classes that implement `INotifyPropertyChanged` generally wind up inheriting some other base class that does the INPC work for it, so still don't get to choose their base class. In any case, inability to inherit any other base class has never been an _actual_ issue for me. If there is a base class I want to inherit in a view-model, it already inherits `DependencyObject` (because it itself is a view-model class). – Peter Duniho Oct 17 '15 at 03:09
  • @JohnathonSullinger: As for "overhead", well...a) WPF's binding system is highly optimized and takes `DependencyObject` into account, and b) if overhead is such a big concern that that's an argument against using `DependencyObject`, then WPF really isn't the API for you. – Peter Duniho Oct 17 '15 at 03:09
  • I disagree. You're using something in a manor it wasn't intended to be used for. Introduce someone fresh to your projects and they'll be confused pretty quickly. Every piece of documentation on MSDN has you using INPC. You have to explain and educate someone as to why you deviated from the official guidance from MSFT every time they join your project, and violated the "No view stuff in your VM" which is what DependencyObject was designed for. – Johnathon Sullinger Oct 17 '15 at 03:12
  • @JohnathonSullinger: all due respect, your dogma is showing. You might consider broadening your view a bit. There is ample precedent for the use of DP in view-model, and in fact doing is [_documented_](https://msdn.microsoft.com/en-us/library/bb613546(v=vs.100).aspx) as being more efficient in binding scenarios, something that is [backed up by testing](http://blog.quantumbitdesigns.com/2010/01/26/mvvm-lambda-vs-inotifypropertychanged-vs-dependencyobject/). – Peter Duniho Oct 17 '15 at 03:45
  • @JohnathonSullinger: A Microsoft Partner on TechNet even [includes DP as a viable view-model implementation](http://social.technet.microsoft.com/wiki/contents/articles/13536.easy-mvvm-examples-in-extreme-detail.aspx). There is also ample ambivalence among other WPF developers [on Stack Overflow](http://stackoverflow.com/q/291518/3538012). It's also notable that nothing in the documentation for [`DependencyObject`](https://msdn.microsoft.com/en-us/library/system.windows.dependencyobject(v=vs.110).aspx) suggests DP should be limited to UI objects. – Peter Duniho Oct 17 '15 at 03:45
  • @Peter what does the dependency class code look like. Or I'd it already a defined class. – JokerMartini Oct 17 '15 at 12:13
  • @Peter what are some of the downsides to using dependency object and things to be aware of when using it ? – JokerMartini Oct 17 '15 at 12:14
  • @JokerMartini: [`DependencyObject`](https://msdn.microsoft.com/en-us/library/system.windows.dependencyobject(v=vs.110).aspx) is built into the framework. I'll add to my answer a brief summary of things that may affect your choice of whether to use it or not. – Peter Duniho Oct 17 '15 at 16:01
  • thank you i appreciate it Peter. Great work once again. – JokerMartini Oct 17 '15 at 17:21
  • @Peter do you happen to have an email, i wanted to ask you a few questions without filling up this with a chat. my gmail is jokermartini@gmail.com – JokerMartini Oct 17 '15 at 17:26
  • @JokerMartini: I ask that all Stack Overflow-related discussions that I participate in take place on SO. For quick commentary/clarifications, comments are fine. For things which require detailed response, the Q&A format of SO is ideal, and preserves the information for others should they also have the same question(s) (i.e. post a new question). – Peter Duniho Oct 17 '15 at 20:34
  • completely understand and agree. im fine with that! thank you – JokerMartini Oct 17 '15 at 21:24