INotifyPropertyChanged
Dès que l’on veut faire du binding, on recontre l’interface INotifyPropertyChanged.
Cette interface ne contient qu’un évènement :
event PropertyChangedEventHandler PropertyChanged;
On utilise généralement cet évènement comme ceci :
protected virtual void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
Sauf que je déconseille formellement de travailler comme ceci. En effet, je refuse de passer le nom de la propriété en chaine de caractères (possibilité de faire des fautes de frappes, pas de refactoring et erreur qu’au moment de l’exécution). Le pire dans le cas d’une faute de frappe ou d’un renomage non répercuté de la propriété c’est que même à l’exception, on n’aura pas d’exception et on risque de perdre du temps à comprendre pourquoi le contrôle bindé n’est pas rafraîchit lorsque la propriété sur laquelle il est bindé change.
D’où l’idée de récupérer le nom de la propriété par code.
Pour cela, on peut utiliser les arbres d’Expressions :
public void RaisePropertyChanged<T>(Expression<Func<T>> exp)
{
string propertyName = PropertyName.GetPropertyName(exp);
if (propertyName != null)
RaisePropertyChanged(propertyName);
}
public static class PropertyName
{
public static string GetPropertyName(LambdaExpression exp)
{
var memberExpression = exp.Body as MemberExpression;
if (memberExpression != null)
return memberExpression.Member.Name;
return null;
}
}
Du coup, au lieu d’écrire ceci :
RaisePropertyChanged("MyProperty");
On va écrire ceci :
RaisePropertyChanged(() => MyProperty);
C’est déjà une bonne amélioration à mon avis.
Ensuite se pose le problème de la factorisation. En effet, on ne va pas faire ça sur chaque classe. On pourrait se faire une classe de base NotifyPropertyChanged mais C# ne supportant pas le multi-héritage ce n’est pas l’idéal d’où l’idée de préférer l’encapsulation à l’héritage dans ce cas.
public class NotifyPropertyChanged
{
private Func<PropertyChangedEventHandler> _getRaiseEvent;
private object _sender;
public NotifyPropertyChanged(object sender, Func<PropertyChangedEventHandler> getRaiseEvent)
{
_getRaiseEvent = getRaiseEvent;
_sender = sender;
}
public void RaisePropertyChanged(string propName)
{
PropertyChangedEventHandler propertyChanged = _getRaiseEvent();
if (propertyChanged != null)
propertyChanged(_sender, new PropertyChangedEventArgs(propName));
}
public void RaisePropertyChanged<T>(Expression<Func<T>> exp)
{
string propertyName = PropertyName.GetPropertyName(exp);
if (propertyName != null)
RaisePropertyChanged(propertyName);
}
}
Ainsi, la classe qui implémentera l’interface INotifyPropertyChanged aura juste à faire ceci :
public event PropertyChangedEventHandler PropertyChanged;
private NotifyPropertyChanged _notifyPropertyChanged;
protected NotifyPropertyChanged NotifyPropertyChanged
{
get { return _notifyPropertyChanged ?? (_notifyPropertyChanged = new NotifyPropertyChanged(this, () => PropertyChanged)); }
}
Pour l’utiliser, il suffira d’écrire ceci :
NotifyPropertyChanged.
RaisePropertyChanged(() => MyProperty);
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :