I've found that typing and re-typing the same property getters and setters that raise the property changed event to be tedious and also potentially error-prone because property names are passed as typed strings. After searching for an easier way to do that, I created the following generic class:
public class ObservableProperty<T> : INotifyPropertyChanged
{
private T _backingField;
public T Value
{
get { return this._backingField; }
set
{
if (!EqualityComparer<T>.Default.Equals(this._backingField, value))
{
this._backingField = value;
this.TriggerPropertyChangedEvent();
}
}
}
/// <summary>
/// Creates an observable property with a default initial value.
/// </summary>
public ObservableProperty() : this(default(T)) { }
/// <summary>
/// Creates an observable property with the specified initial value.
/// </summary>
/// <param name="initialValue">The value to initialize the observable property to.</param>
public ObservableProperty(T initialValue)
{
this.Value = initialValue;
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected void TriggerPropertyChangedEvent([CallerMemberName]string propertyName = null)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion // INotifyPropertyChanged Implementation
}
Now instead of implementing INotifyPropertyChanged on the entire ViewModel and typing out all backing fields and property getters and setters long-hand, all that has to be done is:
public ObservableProperty<string> BindableText { get; private set; }
And then in the constructor:
this.BindableText = new ObservableProperty<string>("Default Text");
The view will now bind to BindableText.Value in the XAML.
So each property will have its own implementation of INotifyPropertyChanged, becoming a mini view model on its own, and the models and view models that create instances of these will not need to implement the interface at all.
This works fine and properties that can be bound to are very easy to create. ViewModels can even reference observable properties that are on the models like:
public ObservableProperty<int> MyNumber { get { return MyModel.Number; } }
so that views do not bind directly to properties on models, only indirectly through their view models.
The question I have, since it's not something I have a lot of experience with, is will there be any potential soft memory leaks by taking this approach that I could take measures against somehow?