views:

1100

answers:

2

I want to add a dependency property to a UserControl that can contain a collection of UIElement objects. You might suggest that I should derive my control from Panel and use the Children property for that, but it is not a suitable solution in my case.

I have modified my UserControl like this:

public partial class SilverlightControl1 : UserControl {

  public static readonly DependencyProperty ControlsProperty
    = DependencyProperty.Register(
      "Controls",
      typeof(UIElementCollection),
      typeof(SilverlightControl1),
      null
    );

  public UIElementCollection Controls {
    get {
      return (UIElementCollection) GetValue(ControlsProperty);
    }
    set {
      SetValue(ControlsProperty, value);
    }
  }

}

and I'm using it like this:

<local:SilverlightControl1>
  <local:SilverlightControl1.Controls>
    <Button Content="A"/>
    <Button Content="B"/>
  </local:SilverlightControl1.Controls>
</local:SilverlightControl1>

Unfortunately I get the following error when I run the application:

Object of type 'System.Windows.Controls.Button' cannot be converted to type
'System.Windows.Controls.UIElementCollection'.

In the Setting a Property by Using a Collection Syntax section it is explicitly stated that:

[...] you cannot specify [UIElementCollection] explicitly in XAML, because UIElementCollection is not a constructible class.

What can I do to solve my problem? Is the solution simply to use another collection class instead of UIElementCollection? If yes, what is the recommended collection class to use?

+1  A: 

If you're using the Silverlight Toolkit, the System.Windows.Controls.Toolkit assembly contains an "ObjectCollection" which was designed to make this kind of thing easier to do in XAML.

It does mean that your property would need to be of type ObjectCollection to work, so you lose your strong typing to UIElement. Alternatively, if it is an IEnumerable type (like most ItemsSource), you could explicitly define the toolkit:ObjectCollection object in XAML.

Consider using that, or simply borrowing the source to ObjectCollection (Ms-PL) and using it in your project.

There may be a way to get the parser to actually work in a collection scenario, but this feels a little easier.

I'd also recommend adding a [ContentProperty] attribute so that the design-time experience is a little cleaner.

Jeff Wilcox
Thanks for your input and nice comment about `ContentProperty` (which doesn't apply in my case).
Martin Liversage
+2  A: 

I changed the type of my property from UIElementCollection to Collection<UIElement> and that seems to solve the problem:

public partial class SilverlightControl1 : UserControl {

  public static readonly DependencyProperty ControlsProperty
    = DependencyProperty.Register(
      "Controls",
      typeof(Collection<UIElement>),
      typeof(SilverlightControl1),
      new PropertyMetadata(new Collection<UIElement>())
    );

  public Collection<UIElement> Controls {
    get {
      return (Collection<UIElement>) GetValue(ControlsProperty);
    }
  }

}

In WPF UIElementCollection has some functionality to navigate the logical and visual tree, but that seems to be absent in Silverlight. Using another collection type in Silverlight doesn't seem to pose any problem.

Martin Liversage
Even easier - glad it works. When I tried it, I forgot to set the initial property metadata to an instance of the collection.
Jeff Wilcox