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:
- It is read-only. This is not common, but of course can work in some situations.
- 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:
- 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.
- 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.