根据选择切换ListBoxItem的ContentPresenter

发布于 2024-11-14 03:01:09 字数 3484 浏览 8 评论 0原文

我试图在选择 ListBoxItem 时切换其 ContentPresenter,同时使用多个 DataTemplate 来表示不同类型的数据。

下面是定义内部 ListBox 的 UserControl:

<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/expression/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>

根据要显示的数据类型(例如,“Header Slug”),将特定的 DataTemplate 应用到 ListBoxItem。这工作得很好,但我想根据显示的数据类型将所选 ListBoxItem 的 DataTemplate 调整为不同的 DataTemplate。

目标是,由于每种数据类型都不同,因此每种数据类型在未选择时将具有独特的外观,并且在选择时将收到一组唯一的选项。

如果我能实现上述工作,那就太好了!但是,我也想让事情变得复杂......

虽然每种数据类型都有独特的控件,但它们也有通用的控件。因此,我理想地希望将所有公共控件定义一次,以便它们出现在列表框中的同一位置。

<DataTemplate x:Key="CommonSelectedTemplate">
    <!-- common controls -->
    ...
    <DataTemplate x:Key="UniqueSelectedTemplate">
        <!-- all the unique controls -->
        <ContentPresenter /> 
    </DataTemplate>
    <!-- more common controls -->
    ...
</DataTemplate>

如果我必须多次定义所有常见的东西(现在)我会活下去。 =)

感谢您的帮助!

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/expression/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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜吻♂芭芘 2024-11-21 03:01:09

假设我们只有两种数据类型:Item1ViewModelItem2ViewModel。因此我们需要4个数据模板:2个用于公共状态,2个用于选定状态。

    <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>

为了根据不同类型在两个模板之间切换内容,我使用 DataTemplateSelector 类:

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;
    }
}

我们需要此选择器的两个实例:一个用于公共状态,一个用于选定状态。

    <local:SampleTemplateSelector x:Key="templateSelector" 
                                  Type1Template="{StaticResource Template1}"
                                  Type2Template="{StaticResource Template2}"/>
    <local:SampleTemplateSelector x:Key="selectedTemplateSelector" 
                                  Type1Template="{StaticResource Template1Selected}"
                                  Type2Template="{StaticResource Template2Selected}"/>

之后,您应该添加此代码来切换两个选择器:

    <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>

就这样,将此 ItemTemplate 应用于您的 ListBox,而不更改 ControlTemplate

<ListBox ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ListItemTemplate}" />

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}" />
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文