【问题标题】:How can I overwrite my ListBox's ItemTemplate and still keep the DisplayMemberPath?如何覆盖我的 ListBox 的 ItemTemplate 并仍然保留 DisplayMemberPath?
【发布时间】:2011-09-20 14:31:13
【问题描述】:

我有一个ListBox 的通用样式,它覆盖ItemTemplate 以使用RadioButtons。效果很好,除非我设置了DisplayMemberPath。然后我只得到ListBox中项目的.ToString()

我觉得我在这里遗漏了一些简单的东西......有人可以帮我发现它吗?

<Style x:Key="RadioButtonListBoxStyle" TargetType="{x:Type ListBox}">
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2, 2, 2, 0" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border Background="Transparent">
                                <RadioButton
                                    Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"
                                    IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>

                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

我的ListBox 绑定到KeyValuePairsList&lt;T&gt;。如果我删除样式,DisplayMemberPath 会正确显示,因此它必须与样式有关。

<ListBox Style="{StaticResource RadioButtonListBoxStyle}"
         ItemsSource="{Binding MyCollection}"
         DisplayMemberPath="Value" SelectedValuePath="Key" />

【问题讨论】:

  • 有点晚了,但是您尝试过 吗?没有将内容属性定义为属性,而是因为 XElement 允许您使用 Contentpresenter-Object,它(在我的情况下是在列表框上)返回 DisplayMemberpath 属性中定义的属性值。未经测试,只是一个想法

标签: wpf templates xaml listbox


【解决方案1】:

您究竟为什么要保留DisplayMemberPath?它只是包含TextBlockItemTemplate 的快捷方式,显示DisplayMemberPath 中的值。使用您自己的ItemTemplate,您可以更灵活地显示想要显示的内容和方式。

只需将TextBlock 添加到您的ItemTemplate 并设置Text="{Binding Value}",您就会得到您想要的。

here所述:

此属性是定义默认模板的简单方法 描述如何显示数据对象。

DisplayMemberPath 提供了一种简单的模板方式,但您需要另一种方式。你不能,也不需要两者。

【讨论】:

  • 因为样式用在大约 5 个不同的地方,所以我想要一个通用的 ItemTemplate 样式
  • 首先,我不会为此重写 Style,我会为您的不同数据类型提供 DataTemplate。因此,您不需要仅仅因为您的数据而更改样式。 ItemContainerStyle 应该只包含外观,DataTemplate 应该包含数据的显示方式。
  • 我正在覆盖样式,因为我想要设置不同级别的多个属性,并且我不想写出三个不同的绑定来使 ListBox 看起来像一个 ComboBox。但是你的回答是不能同时设置DisplayMemberPathItemTemplate
  • 我重新阅读了您在编辑后所说的内容,现在更有意义了
  • 是的,这至少是有意义的。就像我说的。 DisplayMemberPath 只是 imo 为您的项目提供 DataTemplate 的语法糖,添加一个 TextBlock 并将 Text 绑定设置为 DisplayMemberPath 绑定。如果您提供自己的模板,这将不再有效。
【解决方案2】:

我仍然不知道如何使用DisplayMemberPath 来绘制它,但是我确实找到了使用ItemTemplate 绘制它所缺少的部分 - 我需要ContentTemplate 绑定

<RadioButton 
    Content="{TemplateBinding ContentPresenter.Content}" 
    ContentTemplate="{TemplateBinding ContentPresenter.ContentTemplate}"
    IsChecked="{Binding Path=IsSelected,RelativeSource={
                        RelativeSource TemplatedParent},Mode=TwoWay}" />

然后我可以在我的 XAML 中编写:

<ListBox Style="{StaticResource RadioButtonListBoxStyle}"
         ItemsSource="{Binding MyCollection}"
         SelectedValuePath="Key">

    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Value}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

感谢 dowhilefor 指出DisplayMemberPath 只是编写ItemTemplate 的一种快捷方式,不能同时设置两者。

【讨论】:

  • 只是一个旁注,您还应该设置 ContentTemplateSelector,与设置 Content 和 ContentTemplate 的方式相同。在您的情况下,您可能不需要它,但值得指出的是,这是提供项目模板的另一种方式,我记得有一个错误,我们完全忘记了这一点;)
【解决方案3】:

我从早上开始就一直在研究同样的问题,这个帖子对我帮助很大。我调查了解决方案,发现即使在 style 中定义了自定义 ListboxItem 控件模板之后,也有一种方法可以支持 DisplayMemberPath。关键是添加

    ContentTemplateSelector="{TemplateBinding ContentControl.ContentTemplateSelector}"

到 contentpresenter(此线程中的单选按钮)。

这会起作用的原因是因为 displaymemberpath 属性在内部导致列表框将 ContentTemplateSelector 分配给“DisplayMemberTemplateSelector”模板选择器。如果没有这个 TemplateBinding,这个选择器就不会生效。

干杯!

【讨论】:

  • 说的有道理,以后一定要试试。谢谢!
【解决方案4】:

tl;博士

设置一个带有 ContentPresenter 的 ItemContainerStyle,并确保不要覆盖 ItemTemplate。

需要

您想定义一个通用样式以重复使用。

您希望对不同的数据类型重复使用它,因此您希望在重复使用时能够使用 DisplayMemberPath 或 ItemTemplate - 而不必重新定义整个样式。

问题

您没有在项目的容器上使用 ContentPresenter。
项目本身将无处可画。

解决办法

具体情况

在 RadioButton 中放置一个 ContentPresenter;这应该工作:

<RadioButton IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"
             VerticalAlignment="Center">
    <ContentPresenter />
</RadioButton>

一般

定义 ItemContainerStyle。这使您可以控制每个项目的包装方式。

该样式以 ListBoxItem 为目标。

定义该样式的模板,确保包含一个 ContentPresenter(将显示项目本身的内容)。

一个样本

定义风格
<Style TargetType="{x:Type ListBoxItem}" x:Key="BigListBoxItemStyle" BasedOn="{StaticResource DefaultListBoxItemStyle}">
    <Setter Property="Foreground" Value="DeepPink" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="Height" Value="71" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="BorderBrush" Value="Transparent" />
    <Setter Property="Padding" Value="10 5 10 5" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border Background="{TemplateBinding Background}"
                        Margin="{TemplateBinding Margin}"
                        BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="1" />
                        </Grid.RowDefinitions>
                        <ContentPresenter Grid.Row="0" Grid.Column="0"
                                          Margin="{TemplateBinding Padding}"
                                          VerticalAlignment="Center" />
                        <Rectangle x:Name="GraySeparator"
                                   Grid.Row="1"
                                   Height="1" Stroke="Gray" Opacity="0.2"
                                   HorizontalAlignment="Stretch" VerticalAlignment="Bottom" />
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True" >
                        <Setter Property="Background" Value="Yellow" />
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True" >
                        <Setter Property="BorderBrush" Value="DarkGreen" />
                        <Setter Property="Visibility" Value="Hidden" TargetName="GraySeparator" />
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Opacity" Value=".5" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="BigListBoxStyle" TargetType="{x:Type ListBox}">
    <Setter Property="ItemContainerStyle" Value="{StaticResource BigListBoxItemStyle}" />
</Style>
使用它
<ListBox Style="{StaticResource BigListBoxStyle}"
         ItemsSource="{Binding MyTuples}"
         DisplayMemberPath="Item2"
         SelectedItem="{Binding SelectedTuple}">

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2020-07-24
    • 2018-04-21
    相关资源
    最近更新 更多