PREMISE
In a default MVVM scenario, your ViewModel don't have to raise notifications on every property.
Typical case: you get some Person
from a database, show them on a View, modify them via TextBoxes
and other controls, and click "Save" re-sending them to the database. You can do this by setting the DataContext
on the View every time you call the database. This action raises a first update on the bound properties of the control and of every sub-control, so all the getters of the ViewModel's bound properties are called one time and the View get populated with the ViewModel's values. When you modify something on the View, that binding carries the modification to the corresponding ViewModel's property (even a simple plain get-set property).
In this case, you're just fine with something like:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
//and so on...
}
You need to raise notifications for the ViewModel's properties only if the View must listen to some property's change. For example, this feature: the Button
"Save" is enabled if and only if the Name
on the Person
is not empty. Here, clearly the Button
must be able to see when the Name
property changes, so that property setter must raise the PropertyChanged
event.
A possible implementation:
Use this as base class for ViewModels:
protected abstract BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetAndNotifyIfChanged<T>(
ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
NotifyPropertyChanged(propertyName);
}
}
}
In a derived class you can write every get-set property like this:
class MyViewModel : BaseViewModel
{
public string MyProp
{
get { return _MyProp; }
set { SetAndNotifyIfChanged(ref _MyProp, value); }
}
private string _MyProp;
}
The type T
and the parameter propertyName
are automatically inferred.
This is the shortest piece of code you could write, and is not so different from a normal full-property:
public string NormalProp
{
get { return _ NormalProp; }
set { _NormalProp = value; }
}
private string _MyProp;
If you don't want to write all this code every time, use a code snippet.