views:

135

answers:

1

The following is similar to what I'm trying to accomplish. However, I get an "Invalid PropertyDescriptor value" error on the Template Setter. I suspect it's because I didn't specify a target type for the Style; however, I don't know the container type for ItemsControl.

<ItemsControl>
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <StackPanel>
                            <TextBlock Text="Some Content Here" />
                            <ContentPresenter />
                            <Button Content="Edit" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.Items> <!-- heterogenous controls -->
        <Button Content="Content 1" />
        <TextBox Text="Content 2" />
        <Label Content="Content 3" />
    </ItemsControl.Items>
</ItemsControl>
+2  A: 

You can qualify the property name with the type name:

<Setter Property="Control.Template">

The container for ItemsControl is normally a ContentPresenter, but if the child is a UIElement then it won't use a container. In this case, all of the children are Controls, so the ItemContainerStyle will apply to them directly. If you added an item other than a UIElement, that setter would set the Control.Template property on the ContentPresenter, which would succeed but have no effect.

Actually, it sounds like what you want is to wrap each child in a container, even if they are already a UIElement. To do that, you will have to use a subclass of ItemsControl. You could use an existing one like ListBox, or you could subclass ItemsControl and override GetContainerForItemOverride and IsItemItsOwnContainerOverride to wrap the items in your own container. You could wrap them in a ContentControl and then use that as the TargetType for the Style.

public class CustomItemsControl
    : ItemsControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ContentControl();
    }

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        // Even wrap other ContentControls
        return false;
    }
}

You will also need to set the TargetType on the ControlTemplate so that the ContentPresenter will bind to the Content property:

<ControlTemplate TargetType="ContentControl">
Quartermeister
Works swimmingly! I was trying to do all of it with XAML, and just a few lines of code to derive a class makes it all happy, neat and clean.
Travis Heseman