/ Wpf

Strongly typed property change callbacks for a dependency property

It was annoying me for a long time: whenever you need a property changed handler for a dependency property, in that handler you almost always need to cast arguments to types you need:

public static readonly DependencyProperty FooProperty =
    DependencyProperty.RegisterAttached(
        "Foo", 
        typeof(MyClass), 
        typeof(MyControl), 
        new UIPropertyMetadata(null, OnFooChanged));
 
 
private static void OnFooChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{
    var myControl = (MyControl) d;
    var fooValue = (MyClass) e.NewValue;
    ... 
}

Then I came up with a helper that allows me to specify a strongly typed callback:

public static readonly DependencyProperty FooProperty =
    DependencyProperty.RegisterAttached(
      "Foo", 
      typeof(MyClass), 
      typeof(MyControl), 
      new UIPropertyMetadata(null, DependencyPropertyHelper.ChangedCallback<MyControl, MyClass>(OnFooChanged)));
 
 
private static void OnFooChanged(MyControl d, DependencyPropertyChangedEventArgs<MyClass> e) 
{
    // You don't need to declare these variables anymore, because all the arguments of this
    // callback are already strongly typed.
    var myControl = d; // Already has a type of MyControl
    var propertyValue = e.NewValue; // Already has a type of MyClass
    ... 
}

This results in cleaner and more error-proof code, because all the types for the property declared in one place.

Here is the source code of that helper:

public delegate void PropertyChangedCallback<in TObject, TProperty>(
    TObject d, 
    DependencyPropertyChangedEventArgs<TProperty> e) where TObject : DependencyObject;
 
public static class DependencyPropertyHelper
{
    public static PropertyChangedCallback ChangedCallback<TObject,TProperty>(PropertyChangedCallback<TObject,TProperty> callback) where TObject : DependencyObject 
    {
        return (o, e) => callback((TObject) o, new DependencyPropertyChangedEventArgs<TProperty>(e));
    }
}
 
public class DependencyPropertyChangedEventArgs<TProperty> 
{
    public DependencyPropertyChangedEventArgs(DependencyPropertyChangedEventArgs originalEventArgs) 
    {
        OriginalEventArgs = originalEventArgs;
    }
 
    public TProperty NewValue { get { return (TProperty) OriginalEventArgs.NewValue; }}
    public TProperty OldValue { get { return (TProperty) OriginalEventArgs.OldValue; }}

    public DependencyPropertyChangedEventArgs OriginalEventArgs { get; private set; }
}
Pavlo Glazkov

Pavlo Glazkov

Programmer. Full stack, with a focus on UI. JavaScript/TypeScript, Angular, Node.js, .NET

Read More