Adding Custom Collections to your Silverlight Controls

When building custom controls, you often need to allow the user to add a collection of items to the control either programmatically or through XAML declaration.  For example, suppose you are building a menu control and you need to allow the users of your control to add controls as children to your control.  The ListBox is one such example:

<ListBox Width="100" Height="300">
    <ListBoxItem Content="Testing1"></ListBoxItem>
    <ListBoxItem Content="Testing2"></ListBoxItem>
    <ListBoxItem Content="Testing3"></ListBoxItem>
</ListBox>

Each of the ListBoxItems are child controls of the ListBox control.  The ListBox arranges these child controls according to the logic contained in the ListBox control.  We can almost accomplish the same thing in our own controls with a minimal amount of logic.  I say almost because we cannot directly place the collection items as content to our parent control.  This is because custom ContentProperties are not supported for custom controls in SL2B2.  The workaround has the following form:

<local:Container>
<local:Container.Items>
    <local:ContainerItemCollection>
        <local:ContainerItem Text="Hello" />
        <local:ContainerItem Text="Silverlight" />
        <local:ContainerItem Text="World!" />
    </local:ContainerItemCollection>
</local:Container.Items>

</local:Container>

We can achieve the above syntax by adding an Items dependency and corresponding public wrapper property to our control class:

public static DependencyProperty ItemsProperty = DependencyProperty.Register(
    "Items",
    typeof (ContainerItemCollection),
    typeof (Container),
    null);

public ContainerItemCollection Items
{
    get { return this.GetValue(ItemsProperty) as ContainerItemCollection; }
    set { this.SetValue(ItemsProperty, value); }
}


In this example, ContainerItemCollection and ContainerItem are defined as follows:

public class ContainerItemCollection : ObservableCollection<ContainerItem>
{
}

public class ContainerItem
{
    public string Text { get; set; }
}


This will work just fine when adding items through your XAML declaration, but suppose you need to programmatically define your item collection at runtime.  In this case, you need to ensure that the collection exists before you begin to add items.  This can be done by adding a check on the Loaded event handler:


// Control Constructor
public Container()
{
    DefaultStyleKey = typeof (Container);
    this.Loaded += new RoutedEventHandler(Container_Loaded);
}

void Container_Loaded(object sender, RoutedEventArgs e)
{
    // Check for null collection and instantiate if it does not exist.
    if (this.Items == null)
        this.Items = new ContainerItemCollection();
}


Now you can add Items through code like so:

MyContainerControl.Items.Add(new ContainerItem { Text = "Hello" });
MyContainerControl.Items.Add(new ContainerItem { Text = "Silverlight" });
MyContainerControl.Items.Add(new ContainerItem { Text = "World!" });

 

I've included a sample project below.  This code worked as of Silverlight 2 Beta 2.  Enjoy!

Download Source Code


Feedback

# Adding Custom Collections to your Silverlight Cont...

Gravatar Bookmarked your post over at Blog Bookmarker.com! 8/22/2008 2:30 PM | zornik

Comments have been closed on this topic.