using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq.Expressions; using Developpez.Dotnet.Linq; namespace Developpez.Dotnet.ComponentModel { /// /// Fournit des méthodes d'extension pour travailler avec les objets implémentant INotifyPropertyChanged. /// public static class NotifyPropertyChangedExtensions { #region Property changed /// /// Ajoute un handler à l'évènement PropertyChanged pour la propriété spécifiée. /// /// Objet à surveiller /// Nom de la propriété à surveiller /// Handler à exécuter quand la valeur de la propriété change /// Un objet IDisposable à supprimer pour se désabonner de l'évènement public static IDisposable OnPropertyChanged(this INotifyPropertyChanged target, string propertyName, PropertyChangedEventHandler handler) { return new DisposablePropertyChangedHandler(target, propertyName, handler); } /// /// Ajoute un handler à l'évènement PropertyChanged pour la propriété spécifiée. /// /// Type de la propriété à surveiller /// Objet à surveiller /// Expression représentant l'accès à la propriété à surveiller /// Handler à exécuter quand la valeur de la propriété change /// Un objet IDisposable à supprimer pour se désabonner de l'évènement public static IDisposable OnPropertyChanged(this INotifyPropertyChanged target, Expression> propertySelector, PropertyChangedEventHandler handler) { string propertyName = LinqHelper.GetPropertyName(propertySelector); return target.OnPropertyChanged(propertyName, handler); } private class DisposablePropertyChangedHandler : IDisposable { private INotifyPropertyChanged _target; private string _propertyName; private PropertyChangedEventHandler _handler; public DisposablePropertyChangedHandler(INotifyPropertyChanged target, string propertyName, PropertyChangedEventHandler handler) { _target = target; _propertyName = propertyName; _handler = handler; _target.PropertyChanged += target_PropertyChanged; } void target_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == _propertyName || e.PropertyName.IsNullOrEmpty()) // null ou vide signifie que toutes les propriétés ont changé { _handler(sender, e); } } #region IDisposable Members public void Dispose() { _target.PropertyChanged -= target_PropertyChanged; _target = null; _propertyName = null; _handler = null; } #endregion } #endregion #region Property dependencies /// /// Commence un bloc de définition des dépendences d'une propriété /// /// Objet pour lequel on définit les dépendences d'une propriété /// Nom de la propriété pour laquelle on définit les dépendences /// Un objet PropertyDependencyManager qui gère les dépendences de la propriété /// Un objet PropertyDependencyManager permet de gérer les dépendences entre différentes propriétés /// de façon à déclencher automatiquement l'évènement PropertyChanged pour les propriétés concernées public static PropertyDependencyManager SetDependenciesFor(this INotifyPropertyChanged target, string propertyName) { return new PropertyDependencyManager(target, propertyName); } /// /// Commence un bloc de définition des dépendences d'une propriété /// /// Type de la propriété à gérer /// Objet pour lequel on définit les dépendences d'une propriété /// Expression représentant l'accès à la propriété pour laquelle on définit les dépendences /// Un objet PropertyDependencyManager qui gère les dépendences de la propriété /// Un objet PropertyDependencyManager permet de gérer les dépendences entre différentes propriétés /// de façon à déclencher automatiquement l'évènement PropertyChanged pour les propriétés concernées public static PropertyDependencyManager SetDependenciesFor(this INotifyPropertyChanged target, Expression> propertySelector) { return target.SetDependenciesFor(LinqHelper.GetPropertyName(propertySelector)); } /// /// Gère les dépendences entre différentes propriétés d'une classe, de façon à déclencher automatiquement /// l'évènement PropertyChanged pour les propriétés concernées. /// public class PropertyDependencyManager { internal PropertyDependencyManager(INotifyPropertyChanged target, string propertyName) { _watchedProperties = new List(); _affectedProperties = new List(); this.Target = target; this.PropertyName = propertyName; } internal INotifyPropertyChanged Target { get; private set; } internal string PropertyName { get; private set; } private List _watchedProperties; private List _affectedProperties; /// /// Permet d'indiquer que la propriété gérée dépend de la propriété spécifiée. /// Si cette propriété change, l'évènement PropertyChanged sera /// également déclenché pour la propriété gérée. /// /// Nom de la propriété dont dépend la propriété gérée /// L'objet PropertyDependencyManager courant public PropertyDependencyManager DependsOn(string propertyName) { _watchedProperties.Add(propertyName); return this; } /// /// Permet d'indiquer que la propriété gérée par cet objet dépend de la propriété spécifiée. /// Si cette propriété change, l'évènement PropertyChanged sera /// également déclenché pour la propriété gérée. /// /// Type de la propriété dont dépend la propriété gérée /// Expression représentant l'accès à la propriété dont dépend la propriété gérée /// L'objet PropertyDependencyManager courant public PropertyDependencyManager DependsOn(Expression> propertySelector) { return DependsOn(LinqHelper.GetPropertyName(propertySelector)); } /// /// Permet d'indiquer que la propriété spécifiée dépend de la propriété gérée par cet objet. /// Si la propriété gérée change, l'évènement PropertyChanged sera /// également déclenché pour la propriété spécifiée. /// /// Nom de la propriété qui dépend de la propriété gérée /// L'objet PropertyDependencyManager courant public PropertyDependencyManager Affects(string propertyName) { _affectedProperties.Add(propertyName); return this; } /// /// Permet d'indiquer que la propriété spécifiée dépend de la propriété gérée par cet objet. /// Si la propriété gérée change, l'évènement PropertyChanged sera /// également déclenché pour la propriété spécifiée. /// /// Type de la propriété affectée par la propriété gérée /// Expression représentant l'accès à la propriété qui dépend de la propriété gérée /// L'objet PropertyDependencyManager courant public PropertyDependencyManager Affects(Expression> propertySelector) { return Affects(LinqHelper.GetPropertyName(propertySelector)); } /// /// Permet d'indiquer l'action à effectuer pour déchencher l'évènement. /// /// Action à effectuer pour déclencher l'évènement. public void Raise(Action raiseEventAction) { this.Target.PropertyChanged += (sender, e) => { if (e.PropertyName.In(_watchedProperties)) { raiseEventAction(this.PropertyName); } if (e.PropertyName == this.PropertyName) { foreach (var prop in _affectedProperties) { raiseEventAction(prop); } } }; } } #endregion } }