Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
Les contrôles n’implémentent pas tous des événements notifiant du changement de valeur de leurs propriétés. Un moyen d’être notifié est d’utiliser le Binding. Voici une classe fournissant des méthodes d’extensions sur les DependencyObject pour ajouter des handlers d’événements.
Ajouter un événement très simple :
ScrollBar sb = new ScrollBar();
sb.AddChangedHandler("Value", (o, e) =>
{
MessageBox.Show(Convert.ToString(e.NewValue));
});
Code :
public static class DependencyObjectExtensions
/// <summary>
/// Inner class bound to the Property we want to monitor
/// </summary>
private class BindingSubscription : DependencyObject, IDisposable
/// Constructor
/// <param name="source">The DependencyObject instance on which we want to monitor the property</param>
/// <param name="name">The PropertyPath to the property we want to monitor</param>
/// <param name="handler">The handler to invoke when the property changed</param>
public BindingSubscription(DependencyObject source, string name, DependencyPropertyChangedEventHandler handler)
this.Handler = handler;
binding = new Binding(name) { Source = source };
this.PropertyPath = name;
BindingOperations.SetBinding(this, ValueProperty, binding);
}
private Binding binding;
/// The PropertyPath to the property we want to monitor
public string PropertyPath { get; set; }
/// The handler to invoke when the property changed
public DependencyPropertyChangedEventHandler Handler { get; set; }
/// Value depedency property.
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(object),
typeof(BindingSubscription),
new PropertyMetadata((d, e) =>
var subscription = ((BindingSubscription)d);
var handler = subscription.Handler;
if (handler != null)
handler(subscription.source, e);
}));
/// Release the binding from the source
public void Dispose()
this.ClearValue(ValueProperty);
/// Get the list of BindingSubscription stored on one object
/// <param name="obj"></param>
/// <returns></returns>
private static List<BindingSubscription> GetListeners(DependencyObject obj)
var list = (List<BindingSubscription>)obj.GetValue(ListenersProperty);
if (list == null)
list = new List<BindingSubscription>();
SetListeners(obj, list);
return list;
/// Set the list of BindingSubscription on an object
/// <param name="value"></param>
private static void SetListeners(DependencyObject obj, List<BindingSubscription> value)
obj.SetValue(ListenersProperty, value);
/// Listeners dependency property
private static readonly DependencyProperty ListenersProperty =
DependencyProperty.RegisterAttached("Listeners", typeof(List<BindingSubscription>), typeof(DependencyObjectExtensions), null);
/// Add a handler to a DependencyProperty for change notification
public static void AddChangedHandler(this DependencyObject source, string name, DependencyPropertyChangedEventHandler handler)
// Create the binding
BindingSubscription subscriber = new BindingSubscription(source, name, handler);
// Store the binding into de DependencyObject to prevent garbage collection of the subscriber
GetListeners(source).Add(subscriber);
/// Remove a handler from a DependencyProperty
public static void RemoveChangedHandler(this DependencyObject source, string name, DependencyPropertyChangedEventHandler handler)
var subscribers = GetListeners(source);
var subscriber = subscribers.FirstOrDefault(s => s.Handler == handler && s.PropertyPath == name);
if (subscriber != null)
subscriber.Dispose();
subscribers.Remove(subscriber);
if (subscribers.Count == 0)
source.ClearValue(ListenersProperty);