#167 – Implementing a Dependency Property That Is A Collection

When you create a custom dependency property that is based on a collection type, you need to define the default value of the property as a new instance of a collection, rather than as just a static value.

For example, we defined the Person.IQ dependency property, with a default value of 100, as follows:

internal static readonly DependencyPropertyKey IQPropertyKey =
    DependencyProperty.RegisterReadOnly("IQ", typeof(int), typeof(Person), new PropertyMetadata(100));

If we define a read-only Person.Friends property, whose type is List<Person>, the same call would look like this:

        internal static readonly DependencyPropertyKey FriendsPropertyKey =
            DependencyProperty.RegisterReadOnly("Friends", typeof(List<Person>), typeof(Person),
              new PropertyMetadata(new List<Person>()));      // Metadata constructor instantiates a new List

#160 – Be Careful When Setting Dependency Property Values from a DependencyObject Constructor

You should normally avoid calling any virtual methods in a C# class constructor.  Your constructor might get called during construction of a derived class, before the derived class has finished initializing everything that it needs to initialize.  If the derived class also overrides the virtual method that you’re calling, that method could end up getting called before the derived class has finished initializing everything (in its constructor).

If you use FxCop to check your code, this will be caught by the DoNotCallOverridableMethodsInConstructors rule.

This rule applies to WPF.  If you set the value of a dependency property in a constructor, virtual methods or callbacks in the property system may end up getting called.

The best way to avoid the problem is to follow the following rule:

  • Initialize all objects that might be used by property system callbacks in your default (parameterless) constructor

See also: Safe Constructor Patterns for DependencyObjects

#159 – Creating a Read-Only Dependency Property

Creating a custom dependency property that is read-only is slightly different from creating a standard dependency property.

  • Use DependencyProperty.RegisterReadOnly, rather than Register
  • Create an internal static copy of a DependencyPropertyKey in addition to a public static DependencyProperty
  • Make the CLR property wrapper read-only

For example, assume that we want to add a read-only IQ property to our Person class.

We register the property as read-only and retrieve a DependencyPropertyKey.

        internal static readonly DependencyPropertyKey IQPropertyKey =
            DependencyProperty.RegisterReadOnly("IQ", typeof(int), typeof(Person), new PropertyMetadata(100));

Although the key is private, we make the property public.

        public static readonly DependencyProperty IQProperty =
            IQPropertyKey.DependencyProperty;

We can still set the value internally, by using the key.

public Person(string first, string last, int iq)
{
    FirstName = first;
    LastName = last;
    SetValue(IQPropertyKey, 100);
}

Finally, we provide a CLR property wrapper.

        public int IQ
        {
            get { return (int)GetValue(IQProperty); }
        }

#158 – When to Create a Custom Dependency Property

When you’re implementing a new class and creating properties of that class, you need to decide for each property whether to make it a full-fledged WPF dependency property.

If a property is a standard CLR property, rather than a dependency property, you can still set property values from XAML.

But you might want to create a custom dependency property if you want your class to do any of the following:

Follow

Get every new post delivered to your Inbox.

Join 110 other followers