Dependency Property Factory

If you have ever developed an application using WPF, you most likely came across dependency properties. At first you love the flexibility of them and what it allows you to do, as they are great! However, after a while you might feel like you are writing a lot of duplicate code, and are filling up entire classes with it. This for me was a strong indication to encapsulate the behaviour and creation of dependency properties as good software design calls for.

To get a quick idea of my proposed solution I’ll simply post two code segments. One taken from an excellent tutorial on dependency properties by Christian Mosers. The other adjusts the code segment using the new approach.

Most common usage:

// Dependency Property
public static readonly DependencyProperty CurrentTimeProperty =
    DependencyProperty.Register(
        "CurrentTime",
        typeof(DateTime),
        typeof(MyClockControl),
        new FrameworkPropertyMetadata(
            DateTime.Now, OnCurrentTimePropertyChanged, OnCoerceTimeProperty
        ));

// .NET Property wrapper
public DateTime CurrentTime
{
    get { return (DateTime)GetValue(CurrentTimeProperty); }
    set { SetValue(CurrentTimeProperty, value); }
}

private static void OnCurrentTimePropertyChanged(
    DependencyObject source,
    DependencyPropertyChangedEventArgs e)
{
    MyClockControl control = source as MyClockControl;
    DateTime time = (DateTime)e.NewValue;
    // Put some update logic here...
}

private static object OnCoerceTimeProperty(DependencyObject sender, object data)
{
    if ((DateTime)data > DateTime.Now)
    {
        data = DateTime.Now;
    }
    return data;
}

// Register the private key to set the value
private static readonly DependencyPropertyKey IsMouseOverPropertyKey =
    DependencyProperty.RegisterReadOnly(
        "IsMouseOver",
        typeof(bool),
        typeof(MyClass),
        new FrameworkPropertyMetadata(false));

// Register the public property to get the value
public static readonly DependencyProperty IsMouseoverProperty =
    IsMouseOverPropertyKey.DependencyProperty;

// .NET Property wrapper
public int IsMouseOver
{
   get { return (bool)GetValue(IsMouseOverProperty); }
   private set { SetValue(IsMouseOverProperty, value); }
}

My proposed solution:

// Enum declaring all the dependency properties present.
public enum Property
{
    CurrentTime,
    IsMouseOver
}

// A factory class used to create and manage the dependency properties.
private static readonly DependencyPropertyFactory<Property> m_properties =
    new DependencyPropertyFactory<Property>(typeof(MyClockControl));

// Public dictionary used to access the dependency properties.
public static readonly Dictionary<Property, DependencyProperty> Properties =
    m_properties.Properties;

[DependencyPropertyAttribute(Property.CurrentTime, DefaultValue=DateTime.Now)]
public DateTime CurrentTime
{
    get { return (DateTime)GetValue(Properties[Property.CurrentTime]); }
    set { SetValue(Properties[Property.CurrentTime], value); }
}

[DependencyPropertyChangedAttribute(Property.CurrentTime)]
private static void OnCurrentTimePropertyChanged(
    DependencyObject source,
    DependencyPropertyChangedEventArgs e)
{
    MyClockControl control = source as MyClockControl;
    DateTime time = (DateTime)e.NewValue;
    // Put some update logic here...
}

[DependencyPropertyCoerceAttribute(Property.DateTime)]
private static object OnCoerceTimeProperty(DependencyObject sender, object data)
{
    if ((DateTime)data > DateTime.Now)
    {
        data = DateTime.Now;
    }
    return data;
}

[DependencyPropertyAttribute(Property.IsMouseOver)]
public bool IsMouseOver
{
   get { return (bool)GetValue(Properties[Property.IsMouseOver]); }
   private set {
       m_properties.SetReadOnlyProperty(this, Properties[Property.IsMouseOver], value);
   }
}

As you might notice, the last code sample has a few advantages.

  • To identify the dependency property an enum is used, still allowing for strong typed identification of the properties.
  • By passing the owner type for the dependency property to the factory class, it is specified in just one place.
  • The settings for a dependency property are placed right above the property which is used in code internally. Parameters you had to pass manually to the DependencyProperty.Register() method before are deduced automatically. You can still specify them manually as well.
  • Although not really visible through this short code sample, adding more properties is really easy and requires a lot less code.
  • Centralized code. In the unlikely event that the Register() method changes, you only have to adjust the code of the factory class.

How it works:
The factory uses reflection to analyse the code to which the attributes are applied. This way it knows the property type and whether the dependency property should be readonly or not. As a name for the property, the ToString() method is used by default.

To be fair I’ll also mention the problems I see with this approach:

  • There is a small overhead to retrieve the dependency property through the Dictionary every time. I do believe this will have a minor impact.
  • Since DependencyObject internally already works with a dictionary, it’s kind of a double effort.
  • The enum value needs to be defined three times for every property. I don’t know an immediate solution for this, but it is relevant for a future post where I’ll discuss data model generation.

Possible expansions:

  • Right now the Dictionary used to make the properties available for public use isn’t read only. Since this class isn’t available by default this might be a subject I’ll address at a later time. Googling for a short amount of time already indicated this is a known problem. Perhaps a custom implementation of Collection can be created to break all references to DependencyProperty.
  • Because the factory controls the creation of the dependency properties, exceptions can be thrown when invalid usage is detected. E.g. When the .NET properties contain more statements than the GetValue() and SetValue().

All things considered I don’t see any major disadvantages, but I’m no WPF expert. I’d love to have some input from people more experienced with WPF.

Factory source code

UPDATE:

Possible problems due to WPF’s naming conventions are discussed in a new post.
For the most recent version, go to my last post for information. For the source code, you can download my FCL Extension library. The DependencyPropertyFactory is located in the Whathecode.PresentationFramework assembly under the namespace Whathecode.System.Windows.DependencyPropertyFactory.

Advertisements
  1. Dependency Property Factory – Part 3 « Whathecode

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: