With a project that uses MVVM (Model-View-View Model) design pattern, INotifyPropertyChanged is often used to detect a property value change in an object. This is particularly pertinent as far as creating a two-way data binding.
Typical Implementation
Normally, the INotifyPropertyChanged is implemented in a similar pattern to the code below. This is something that makes me feel a bit uneasy, especially in terms of maintainability and keeping things tidy, as every property needs to call the method ‘OnPropertyChanged’. All it takes is a typo, a missed call, and it could be hard to spot in a complex application.
The code below is acceptable, but could be simplified through abstraction.
using System.ComponentModel;
public class MyClass : INotifyPropertyChanged
{
private int id { get; set; }
public int Id
{
get { return id; }
set
{
id = value;
OnPropertyChanged(“Id”);
}
}
private string name { get; set; }
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged(“Name”);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Improved using Base Class
Since .NET 4.5, it is possible to harness an attribute called ‘CallerMemberName’. Visual Studio offers this as a base class template called ‘BindableBase’, which allows for a far neater implementation. I can’t take credit for the code below.
///
/// Implementation of to simplify models.
///
[WebHostHidden]
public abstract class BindableBase : INotifyPropertyChanged
{
///
/// Multicast event for property change notifications.
///
public event PropertyChangedEventHandler PropertyChanged;
///
/// Checks if a property already matches a desired value. Sets the property and
/// notifies listeners only when necessary.
///
/// Type of the property.
/// Reference to a property with both getter and setter.
/// Desired value for the property.
/// Name of the property used to notify listeners. This
/// value is optional and can be provided automatically when invoked from compilers that
/// support CallerMemberName.
/// True if the value was changed, false if the existing value matched the
/// desired value.
protected bool SetProperty(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
///
/// Notifies listeners that a property value has changed.
///
/// Name of the property used to notify listeners. This
/// value is optional and can be provided automatically when invoked from compilers
/// that support .
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then any subsequent classes just need to inherit BindableBase.
public class MyViewModel : BindableBase
{
private string _someStringProperty;
public string SomeStringProperty
{
get => _someStringProperty;
set => SetProperty(ref _someStringProperty, value);
}
}
Post Categories