Switch ContentPresenter of ListBoxItem Based on Selection
I am trying to switch out the ContentPresenter of a ListBoxItem when it is selected, while using multiple DataTemplates to represent different types of data.
Here is the UserControl that defines the ListBox inside:
<UserControl x:Class="Homage.View.FilePanelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expressi开发者_JAVA百科on/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vw="clr-namespace:Homage.View"
xmlns:vm="clr-namespace:Homage.ViewModel"
xmlns:ctrl="clr-namespace:Homage.Controls"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate DataType="{x:Type vm:SlugViewModel}">
<vw:SlugView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:HeaderSlugViewModel}">
<vw:HeaderSlugView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ContentSlugViewModel}">
<vw:ContentSlugView />
</DataTemplate>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="SlugContainer" Background="Transparent" BorderBrush="Black" BorderThickness="1" CornerRadius="2" Margin="0,5,0,0" Padding="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Content="{Binding DisplayName}" />
<ContentPresenter Grid.Row="1" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="SlugContainer" Property="BorderThickness" Value="5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<ListBox ItemsSource="{Binding Slugs}" Padding="5" />
</Grid>
</UserControl>
Based on the type of data to be shown (e.g., a "Header Slug") a certain DataTemplate is applied to the ListBoxItem. This is working great, but I am wanting to adjust the DataTemplate of the selected ListBoxItem to a different DataTemplate -- again, based on the data type being shown.
The goal is that, because each data type is different, each would have a unique look when not selected and would receive a unique set of options when selected.
If I can get the above to work, that would be great! But, I also want to complicate things...
While each data type has unique controls they also have common controls. So I would ideally like to define all the common controls once so that they appear in the same place in the ListBox.
<DataTemplate x:Key="CommonSelectedTemplate">
<!-- common controls -->
...
<DataTemplate x:Key="UniqueSelectedTemplate">
<!-- all the unique controls -->
<ContentPresenter />
</DataTemplate>
<!-- more common controls -->
...
</DataTemplate>
If I have to define all the common stuff multiple times (for now) I'll live. =)
Thanks for any help!
Let's suppose that we have only two data types: Item1ViewModel
and Item2ViewModel
. Therefore we need 4 data templates: 2 for the common state, 2 for the selected state.
<DataTemplate x:Key="Template1" DataType="local:Item1ViewModel">
<TextBlock Text="{Binding Property1}" Foreground="Red" />
</DataTemplate>
<DataTemplate x:Key="Template2" DataType="local:Item2ViewModel">
<TextBlock Text="{Binding Property2}" Foreground="Blue" />
</DataTemplate>
<DataTemplate x:Key="Template1Selected" DataType="local:Item1ViewModel">
<TextBlock Text="{Binding Property1}" Background="Yellow" Foreground="Red" />
</DataTemplate>
<DataTemplate x:Key="Template2Selected" DataType="local:Item2ViewModel">
<TextBlock Text="{Binding Property2}" Background="Yellow" Foreground="Blue" />
</DataTemplate>
For switching the content between two templates based on different types I use the DataTemplateSelector
class:
public class SampleTemplateSelector:DataTemplateSelector
{
public DataTemplate Type1Template { get; set; }
public DataTemplate Type2Template { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is Item1ViewModel)
return Type1Template;
else if (item is Item2ViewModel)
return Type2Template;
return null;
}
}
We need two instances of this selector: one for the common state and one for the selected state.
<local:SampleTemplateSelector x:Key="templateSelector"
Type1Template="{StaticResource Template1}"
Type2Template="{StaticResource Template2}"/>
<local:SampleTemplateSelector x:Key="selectedTemplateSelector"
Type1Template="{StaticResource Template1Selected}"
Type2Template="{StaticResource Template2Selected}"/>
And after that you should add this code which switches two selectors:
<DataTemplate x:Key="ListItemTemplate">
<ContentControl x:Name="content" Content="{Binding}" ContentTemplateSelector="{StaticResource templateSelector}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True">
<Setter TargetName="content" Property="ContentTemplateSelector" Value="{StaticResource selectedTemplateSelector}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
That's all, apply this ItemTemplate
to your ListBox
without changing the ControlTemplate
:
<ListBox ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ListItemTemplate}" />
精彩评论