views:

21

answers:

1

I've created a custom control for MahTweets which simplifies/unifies the look of each update across the various social network updates we support. In theory it also simplifies how to theme everything, because we can just create a style for the lookless control.

public class StatusUpdateView : Control
{
    public static readonly DependencyProperty ButtonsProperty = 
        DependencyProperty.RegisterAttached("Buttons", 
            typeof(object), 
            typeof(StatusUpdateTextbox),
            new UIPropertyMetadata(null));
}

Lets just say the above is my existing control's code behind. It has a few other properties but for the large part doesn't matter.

I'm trying to create a 'minimal' theme which hides a lot of the detail, etc, and thats all fine until I get up to the buttons. By moving the buttons (across the networks, buttons change - for example, facebook doesn't have a "retweet" button) I want to go from a grid to a horizontal stackpanel. I want to be able to use the control something like:

<MyControl>
    <MyControl.ContentPartOne>
        <Button/>
        <Button/>
        <Button/>
    </MyControl.ContentPartOne>
    <MyControl.ContentPartTwo>
        <stackpanel>
        ...
        </stackpanel>
    </MyControl.ContentPartTwo>
</MyControl>

That'd allow the style/theme for the custom control to decide the layout of the buttons. Using object (and contentpresenter on the presentation side), I'm told that object can only have one child element (so they were wrapped in grid). I tried to be tricky and do List, which it accepts but doesn't know how to present (so it just gives "(collection)", aka object.ToString())

What do I need on the controls code behind to accept a list of UI element (ala ListBox, Panels, etc), and how do I present it on the UI side?

+1  A: 

What you're describing is the standard pattern of an ItemsControl. ItemsControl takes a collection of objects either directly through Items or bound through ItemsSource (in your case the Buttons) and an ItemsPanelTemplate that defines the Panel to use for layout (your StackPanel). When rendering the ItemsControl's ItemsPresenter then has the ItemsPanel injected into it and filled with the Items. In your case your Items are already Controls so they won't be wrapped with ContentPresenters so you can even use a Grid and it will respect the Grid.Row and Grid.Column settings on your Buttons since they will be direct children.

<ItemsControl>
    <Button Content="1" Grid.Column="0"/>
    <Button Content="2" Grid.Column="1" Grid.Row="1"/>
    <Button Content="3" Grid.Column="2"/>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition/>
                    <ColumnDefinition Width="30"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition Height="50"/>
                </Grid.RowDefinitions>
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

You can either use ItemsControl directly (or HeaderedItemsControl for an extra piece of Content) or derive from it and add more of your own functionality.

John Bowen
Aha! Converted control to extend from ItemsControl,used ItemsPresenter and the set the ItemsPanelTemplate in the theme, all working nowOut of interest, is there anyway to have controls have uhh.. well, two ItemsPresenters like that?
aeoth
Not built in and there's a bunch of code in ItemsControl to drive all those connections to ItemsPresenter that would be a pain to duplicate. If you're getting into situations like that I would recommend just setting up multiple sets of DPs on your custom control (ItemsSource1, ItemsPanel1, ItemsSource2, etc.) as pass-throughs and just use multiple ItemsControls internally in your template.
John Bowen