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
}
}