tags:

views:

198

answers:

3

I've created a custom control that I insert into my window with the following code

<controls:ListExpander Text="Class Diagrams"></controls:ListExpander>

The control in question contains several subcontrols, among others, a list. How can create the setup, so I can specify items that should be added to the list? Eventually I'm looking for the following architecture

<controls:ListExpander Text="Class Diagrams">
  <SomeItem>data<SomeItem>
  <SomeItem>data<SomeItem>
  <SomeItem>data<SomeItem>
  <SomeItem>data<SomeItem>
</controls:ListExpander>

in which case the SomeItem objects should be added to the list in the ListExpander:

    <ListBox Name="lstItems" Background="LightGray">
        <ListBox.Items>
            // Items should go here
        </ListBox.Items>
    </ListBox>

I'm quite new to WPF, but I suppose it's something along the lines of creating a dependency collection on ListExpander that takes object of the type SomeItem?

Edit: Let me clarify a bit. I simply want to be able to give the control a few arguments which it can translate into items in the listbox contained within the the control.

+1  A: 
Erode
A: 

I assume your control contains more than just these children you are looking to add, right? So I would go by adding a property to your control class like this:

private ObservableCollection<UIElement> _items = new ObservableCollection<UIElement>();
public ObservableCollection<UIElement> Items
{
    get { return this._items; }
}

Then in your controls template you just bind your listbox to this collection

<ListBox Name="lstItems" Background="LightGray" ItemsSource="{Binding Items}">
</ListBox>

This way you'll be able to use it like this:

<controls:ListExpander Text="Class Diagrams">
  <controls:ListExpander.Items>
    <SomeItem>data<SomeItem>
    <SomeItem>data<SomeItem>
    <SomeItem>data<SomeItem>
    <SomeItem>data<SomeItem>
  </controls:ListExpander.Items>
</controls:ListExpander>

To be able to use it without the <controls:ListExpander.Items> decorate your class with [ContentProperty("Items")] attribute.

Alan Mendelevich
The binding between Items and lstItems doesn't appear to work. The SomeItem objects are in fact added to _items, but not the listbox.
Qua
Maybe you need to set DataContext in your controls constructor for binding to work. Something like this.DataContext = this; Or use TemplateBinding instead of Binding, or use a longer version of Binding expression specifying RelativeSource. Anyway the principle stands and you just need to find a missing quirk in my sample code.
Alan Mendelevich
A: 

There's a simple way to do it. Add a property of type ItemCollection to your control class like this:

public ItemCollection Items{
    get{
        return innerItems.Items;
    }set{
        innerItems.Items.Clear();
        foreach (var item in value){
            innerItems.Items.Add(item);
        }
    }
}

where innerItems is just an ItemsControl in your XAML (like this):

<UserControl x:Class="TestApp.ItemsExtender"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <StackPanel>
        <Label Content="Control Label" />
        <ItemsControl x:Name="innerItems" />
    </StackPanel>
</UserControl>

then add an attribute to your control class like this:

[ContentProperty("Items")]
public partial class ItemsExtender : UserControl
{...}

this will tell XAML that default items should be assigned to your Items property, and your Items property will use them to populate your inner list collection. You can then consume it like this:

<this:ItemsExtender>
    <Label Content="item1" />
    <Label Content="item2" />
    <Label Content="item3" />
</this:ItemsExtender>

You can extend this sample with type converters to support adding arbitrary things to the collection and dependency properties to support binding, but this should get you started.

Hope it helps!

MKing