October 3rd, 2019

What if I want the default value for a XAML dependency property to be a mutable object?

We saw last time that the default value for a XAML dependency property should be immutable. One easy case of an immutable object is null. But what if you want the default value to be a mutable object?

There’s no perfect answer for this, but the common solution is to set an explicit value in your constructor.

class Light
{
  public Color Color { get; set; }; // read-write property
}

class Widget
{
 ...

 Widget()
 {
  InitializeComponent();
  FrontLight = new Light() { Color = Colors.Red };
 }

 public static readonly DependencyProperty FrontLightProperty =
    DependencyProperty.Register("FrontLight",
    typeof(Light), typeof(Widget));

 // Provide convenient access to the dependency property.
 public Light FrontLight {
  get => (Light)GetValue(FrontLightProperty);
  set => SetValue(FrontLightProperty, value);
 }
}

We define the dependency property with null as its default value, taking advantage of the overload that assumes that you’re okay with null being the default value.

But in our constructor, we explicitly set the value of the Front­Light property to a brand new red light. By explicitly setting a value (known in XAML terminology as setting a local value), we remove the case where XAML needs to produce a default value.

This works out great for most purposes, but there are some subtleties.

One is that the local value is fairly high in the precedence of value sources, sitting above template properties, implicit styles, style triggers, template triggers, style setters, the default style, and inheritance. Setting a local value means that the dependency property cannot be styled, triggered, or inherited.

Another is that somebody might try to reset the property back to the default by calling Clear­Value. In that case, the value of the dependency property returns to the default value, which we implicitly declared as null, rather than returning to the initial value we set in our constructor (the red Light).

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • cheong00

    For the case of .ClearValue(), I think we may change the property to something like this:

    public Light FrontLight {
    get {
    if ((GetValue(FrontLightProperty) == null) && (!m_IsFrontLightCleared)) {
    SetValue(FrontLightProperty, new Light() { Color = Colors.Red });
    }
    return (Light)GetValue(FrontLightProperty);
    }
    set => SetValue(FrontLightProperty, value);
    }

    public new void ClearValue(DependencyProperty dp)
    {
    if (dp == FrontLightProperty) { m_IsFrontLightCleared = true; }
    base.ClearValue(dp);
    }