How do I define a UWP XAML dependency property that is a collection type?

Raymond Chen

Raymond

In XAML, there are at least three ways to specify the contents of a collection-typed dependency property. For concreteness, I’m going to discuss UWP XAML, but the same principle apply to WPF XAML.

Let’s say that we have a Doodad object with a Widgets property. The Widgets property is a collection of Widget objects.

First, we have the implicit collection:

<Doodad>
    <Doodad.Widgets>
        <Widget .../>
        <Widget .../>
        <Widget .../>
    </Doodad.Widgets>
</Doodad>

Second, we have the explicit collection:

<Doodad>
    <Doodad.Widgets>
        <MyWidgetCollection>
            <Widget .../>
            <Widget .../>
            <Widget .../>
        </MyWidgetCollection>
    </Doodad.Widgets>
</Doodad>

Third, we have binding:

<Doodad Widgets="{Binding MyWidgets}" .../>
<Doodad Widgets="{x:Bind MyWidgets}" .../>

Okay, let’s tackle these in order.

The XAML compiler converts the implicit collection into C# code that is roughly equivalent to the below:

var e1 = new Doodad();
var widgets = e1.Widgets;
widgets.Add(new Widget(...));
widgets.Add(new Widget(...));
widgets.Add(new Widget(...));

(You can ask the XAML compiler to generate C++, but I’ll use C# for notational convenience.)

In order for the implicit collection to work, the property must have an initial value that is an empty collection.

The explicit collection compiles to something like this:

var e1 = new Doodad();
var widgets = new MyWidgetCollection();
widgets.Add(new Widget(...));
widgets.Add(new Widget(...));
widgets.Add(new Widget(...));
e1.Widgets = widgets;

In order for explicit collections to work, the property must be settable.

Binding operates like this:

var e1 = FindTheDoodad();
e1.Widgets = this.MyWidgets;

This is equivalent to the explicit collection, so that same solution for explicit collections works for binding, too.

Okay, so how do we set up the dependency property so it satisfies all these requirements?

Turns out this is a special case of what we looked at last time: The dependency property whose initial value is a mutable object. In this case, the mutable object is itself a collection.

public class Doodad
{
  public static readonly DependencyProperty WidgetsProperty =
    DependencyProperty.Register(
      "Widgets",
      typeof(IList<Widget>),
      typeof(Doodad),
      new PropertyMetadata(null));

    public IList<Widget> Widgets
    {
      get => (IList<Widget>)GetValue(WidgetsProperty);
      set => SetValue(WidgetsProperty, value);
    }

    public Doodad()
    {
        this.InitializeComponent();
        Widgets = new List<Widgets>();
    }
  ..
}

Note that the type of the property is IList<Widget> instead of List<Widget>. That way, clients can assign or bind a custom collection.

Bonus chatter: There is documentation on how to create a WPF XAML dependency property that is a collection type, but it makes the mistake of presenting incorrect code first, without any immediate indication that the code is incorrect. I copied the initial code block, since it looked complete, but the result didn’t work. (This is why, in my code samples, I’m careful to note that code in italics is wrong.)

Raymond Chen
Raymond Chen

Follow Raymond   

5 comments

  • Avatar
    Florian Schneidereit

    Since we’re into dependency properties, maybe Raymond can elaborate on why the UWP implementation is missing handy features like property value coercion. The workarounds I heard of are either complex, or break binding scenarios.

    • Avatar
      Joshua Schaeffer

      UWP is a crippled clone of Silverlight which was already a crippled version of WPF missing coercion and a bunch of other things. Even so, it was still insulting to see the Surface Duo running Android instead of UWP. Blaming app support is a hilarious reason to shelve Windows 10 for a joke OS from a lazy competitor whose products look like high school projects; with MS tooling you only need a team of maybe 5 good programmers to write all the apps a mobile device needs. I could even find them for you. You could have made bank for pennies.

      • Avatar
        Florian Schneidereit

        Yes, I know it is kind of a crippled Silverlight, but maybe Raymond can explain why they designed it like that, and not as powerful as WPF.

        App support is indeed a problem. Windows Mobile suffered and eventually died from it. One problem is that PWA never really took of, or still it takes too much time and the outcome is uncertain. If the Top-20-Apps from Android/iOS would all be ready as PWA – putting Windows 10X on a device like the Surface Duo would start to make sense, because at this point it doesn’t matter that native versions of these apps are missing, they would be readily available as PWA.

        And TBH, most UWP apps don’t look and work better than a high school project, either.

        • Avatar
          Joshua Schaeffer

          If MS had put the effort into mobile that they did with console gaming, they would have won. You only had to have a mustard seed of vision and you would have seen it. The tile/flat UI system looked better and was less work. But UWP was never given a complete set of desktop UI controls so there was never a bridge to adoption. Mobile and desktop were under digital apartheid literally isolated to separate XAML universes with no mixing. If you’re doing MVVM right, almost all of your code is in the viewmodels anyway so the XAML facade should be easy to swap, unless you have nothing to swap it with.

Leave a comment