This a follow up to my post about avoiding strings in notifying property change events.
In fact, objects deriving from BindableObject (Views, Pages…) are some of the most common places where we do notify property changes.
These notifications are naturally done using the OnPropertyChanged method of the root BindableObject. Which is presented as:
protected virtual void OnPropertyChanged([string propertyName = null])
Member of Xamarin.Forms.BindableObject Summary:
Call this method from a child class to notify that a change happened on a property. Parameters:
propertyName: The name of the property that changed. Remarks:
A Xamarin.Forms.BindableProperty triggers this by itself. An inheritor only needs to call this for properties without Xamarin.Forms.BindableProperty as the backend store.
|
So if you have a property that requires change notification, you would write:
this.OnPropertyChanged("myPropertyName");
Which brings again the string constant problem: if you, one day, change the name of your property, you should remember visiting all code that may use this name in a string constant… hard and risky labor!
I thought of extending the BindableObject by providing a new OnPropertyChanged method using the Linq.Expressions to avoid string constants. That cannot be straightforward though because the BindableObject's OnPropertyChanged is protected!
For now, I found this solution. Please feel free to change or adapt to your needs. If you may find a better way, I would be happy to hear about your solutions!
The recipe
Define a delegate signature of a method to be called:
public delegate void PropertyChangedHandler(string propertyName);
Define a class for this (and future) extensions:
public static class BindableObjectExtensions
Include this extension method in the class:
public static void OnPropertyChangedExt<TProperty>(this BindableObject obj,
Expression<Func<TProperty>> property,
PropertyChangedHandler propertyChangedHandler)
{
if (property == null || propertyChangedHandler == null)
return;
string name = GetPropertyName(property);
propertyChangedHandler.Invoke(name);
}
The GetPropertyName helper method:
public static string GetPropertyName<TProperty>(Expression<Func<TProperty>> property)
{
if (property == null)
return null;
var expression = property.Body as MemberExpression;
if (expression == null || expression.Member == null)
return null;
return expression.Member.Name;
}
Sample usage
public class TestBindableExtension: BindableObject
{
string _test = "Test";
public string TestProperty
{
get { return _test; }
set
{
_test = value;
this.OnPropertyChangedExt(() => TestProperty, this.OnPropertyChanged);
}
}