The blog of dlaa.me

Freedom isn't free [Tip: When creating a DependencyProperty, follow the handy convention of "wrapper+register+static+virtual"]

Tip

When creating a DependencyProperty, follow the handy convention of "wrapper+register+static+virtual"

Explanation

The fundamental steps for defining a Silverlight/WPF DependencyProperty are fairly rigid and not open to a great deal of flexibility (as I discuss in this earlier tip about the CLR wrapper). However, there's a bit more freedom once you add a default value or a PropertyChangedCallback delegate to the mix - but don't let it go to your head! :) For convenience and flexibility, I recommend the pattern shown below; the same one used by most of the core Silverlight and WPF controls. Observe that while the PropertyMetadata constructor requires a static delegate for property change notifications, doing instance-specific work in a static method is inconvenient. Therefore, the static method below does the bare minimum before handing execution off to a more appropriate instance method. (Aside: Explicit casts are safe because the DependencyProperty infrastructure is responsible for honoring the contract of the Register call.) The extra level of indirection also provides an opportunity to pass more meaningful parameters to the change handler: the property's old value and its new value. And because the instance method is virtual, subclasses can override it to receive their own notification of property changes easily and efficiently. Working with DependencyProperty can be tricky enough; do yourself a favor and start with a solid foundation.

Good Example

public int MyProperty
{
    get { return (int)GetValue(MyPropertyProperty); }
    set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
    "MyProperty", typeof(int), typeof(MyControl), new PropertyMetadata(0, OnMyPropertyChanged));
private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((MyControl)d).OnMyPropertyChanged((int)e.OldValue, (int)e.NewValue);
}
protected virtual void OnMyPropertyChanged(int oldValue, int newValue)
{
    // TODO: Handle property change
}

More information