Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify ControlTemplate for ItemsControl.ItemContainerStyle

The following is similar to what I'm trying to accomplish. However, I get the error

Invalid PropertyDescriptor value.

on the Template Setter. I suspect it's because I didn't specify a TargetType 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>
    <!-- heterogenous controls -->
    <ItemsControl.Items> 
        <Button Content="Content 1" />
        <TextBox Text="Content 2" />
        <Label Content="Content 3" />
    </ItemsControl.Items>
</ItemsControl>
like image 594
Travis Heseman Avatar asked Aug 22 '10 16:08

Travis Heseman


2 Answers

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">
like image 182
Quartermeister Avatar answered Oct 18 '22 06:10

Quartermeister


Also if you only want to do all of it with XAML you can simply use ListBox instead of ItemsControl and define a style for ListBoxItem:

        <ListBox ItemsSource="{Binding Elements.ListViewModels}">
        <ListBox.Resources>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <StackPanel>
                                <TextBlock>Some Content Here</TextBlock>
                                <ContentPresenter Content="{TemplateBinding Content}" />
                                <Button>Edit</Button>
                            </StackPanel>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Resources>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>

Note that because I am using ListBox the container is ListBoxItem(Generally the container for WPF's default list control is always named the Item) so we create a style for ListBoxItem:

<Style TargetType="ListBoxItem">

Then we create a new ControlTemplate for ListBoxItem. Please note that ContentPresenter is not used as it always appears in articles and tutorials, you need to template-bind it to Content property of ListBoxItem, so it will show the content for that item.

<ContentPresenter Content="{TemplateBinding Content}" />

I just had the same problem and fixed it this way. I dont wanted some functionalities of ListBox ( item selection ) and by using this technique the item selection does not work anymore.

like image 41
000 Avatar answered Oct 18 '22 07:10

000