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>
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">
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With