如何覆盖ListBox的ItemTemplate并仍保留DisplayMemberPath?

时间:2011-09-20 14:31:14

标签: wpf templates xaml listbox

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

我觉得我在这里缺少一些简单的东西......有人能帮助我发现它吗?

<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绑定了List<T> KeyValuePairs。如果我删除了样式,则DisplayMemberPath会正确显示,因此它必须是样式的内容。

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

4 个答案:

答案 0 :(得分:9)

为什么要保留DisplayMemberPath?它只是包含TextBlock的ItemTemplate的快捷方式,显示DisplayMemberPath中的值。使用您自己的ItemTemplate,您可以更灵活地显示您想要显示的内容和方式。 只需在ItemTemplate中添加一个TextBlock并设置Text="{Binding Value}"即可获得所需内容。

如上所述here

  

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

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

答案 1 :(得分:3)

我仍然无法弄清楚如何使用DisplayMemberPath来绘制它,但是我确实找到了我缺少的那块以使用ItemTemplate绘制它 - 我需要{{} 1}}绑定

ContentTemplate

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

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

感谢dowhilefor指出<ListBox Style="{StaticResource RadioButtonListBoxStyle}" ItemsSource="{Binding MyCollection}" SelectedValuePath="Key"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Value}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> 只是写DisplayMemberPath的快捷方式,而且两者都不能一次设置。

答案 2 :(得分:3)

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

    ContentTemplateSelector="{TemplateBinding ContentControl.ContentTemplateSelector}"

到contentpresenter(在这个帖子的情况下是radiobutton)。

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

干杯!

答案 3 :(得分:0)

TL;博士

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

需要

您想要定义要重复使用的通用样式。

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

问题

您没有在商品的容器上使用ContentPresenter 该项目本身无处可绘。

解决方案

针对您的具体案例

将ContentPresenter放入RadioButton中;应该工作:

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

一般

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

该Style以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}">