在ComboBoxItem模板中使用DisplayMemberPath

5

目前,我已经硬编码了应该显示的DataContext对象的属性(DisplayName)。但通常情况下,您会在ComboBox本身中使用DisplayMemberPath属性指定此路径。我如何使用由DisplayMemberPath指定的值作为要绑定到内容呈现器中的属性?

<Style TargetType="{x:Type ComboBoxItem}">
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Border x:Name="ItemBorder"
                            Padding="2,0"
                            BorderThickness="1"
                            CornerRadius="3">


                        <ContentPresenter Content="{Binding DisplayName}"/>


                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger SourceName="ItemBorder" Property="IsMouseOver" Value="True">
                            <Setter TargetName="ItemBorder" Property="Background" Value="{StaticResource LightBlueBackgroundBrush}"/>
                            <Setter TargetName="ItemBorder" Property="BorderBrush" Value="{StaticResource LightBlueBackgroundBrush}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

以下是我的ComboBox样式,供参考。

<Style TargetType="{x:Type ComboBox}">
    <Setter Property="SnapsToDevicePixels" Value="True" />
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="Height" Value="22"/>
    <Setter Property="Background" Value="White"/>
    <Setter Property="BorderBrush" Value="{StaticResource MidGreyBorderStroke}"/>
    <Setter Property="Border.CornerRadius" Value="3" />
    <Setter Property="IsEditable" Value="False" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBox}">

                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="1"
                        CornerRadius="{TemplateBinding Border.CornerRadius}"
                        Width="{TemplateBinding Width}"
                        Height="{TemplateBinding Height}">

                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <ContentPresenter x:Name="ReadOnlyContentPresenter"
                                          Grid.Column="0"
                                          Margin="5,0"
                                          VerticalAlignment="Center"
                                          HorizontalAlignment="Left"
                                          Content="{TemplateBinding SelectionBoxItem}"
                                          ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                                          ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" />

                        <TextBox x:Name="PART_EditableTextBox"
                                 Grid.Column="0"
                                 Margin="5,0"
                                 VerticalAlignment="Center"
                                 HorizontalAlignment="Center"
                                 Visibility="Hidden"
                                 IsReadOnly="{TemplateBinding IsReadOnly}" />

                        <Border Grid.Column="1"    
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="1,0,0,0"
                                Margin="0,2" />

                        <ToggleButton Grid.Column="2"
                                      Margin="1,0"
                                      Background="{TemplateBinding Background}"
                                      VerticalAlignment="Center"
                                      HorizontalAlignment="Right"
                                      Focusable="False"
                                      IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                                      ClickMode="Press"
                                      Style="{StaticResource ComboBoxToggleButton}"/>

                        <Popup x:Name="PART_Popup"
                               AllowsTransparency="True"
                               Placement="Bottom"
                               IsOpen="{TemplateBinding IsDropDownOpen}"
                               Focusable="False"
                               PopupAnimation="Fade"
                               SnapsToDevicePixels="True">

                            <Grid Background="Transparent"
                                  MinWidth="{TemplateBinding ActualWidth}"
                                  MaxHeight="{TemplateBinding MaxDropDownHeight}">

                                <Border x:Name="DropDownBorder"
                                        Background="{TemplateBinding Background}"
                                        BorderBrush="{TemplateBinding BorderBrush}"
                                        BorderThickness="1"
                                        CornerRadius="{TemplateBinding Border.CornerRadius}"
                                        Margin="0,2,0,0">

                                    <ScrollViewer Margin="6,0">
                                        <StackPanel IsItemsHost="True"
                                                    KeyboardNavigation.DirectionalNavigation="Contained" />
                                    </ScrollViewer>
                                </Border>
                            </Grid>
                        </Popup>
                   </Grid>
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Opacity" Value=".65" />
                    </Trigger>

                    <Trigger Property="HasItems" Value="false">
                        <Setter TargetName="DropDownBorder" Property="MinHeight" Value="42"/>
                    </Trigger>

                    <Trigger Property="IsEditable" Value="True">
                        <Setter Property="IsTabStop" Value="false"/>
                        <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
                        <Setter TargetName="ReadOnlyContentPresenter" Property="Visibility" Value="Hidden"/>
                    </Trigger>
                </ControlTemplate.Triggers>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
2个回答

9
这是一个有趣的问题,但答案非常简单。
简短回答:
   <ContentPresenter />

长答案:

如果您已经重写了ComboBoxItem样式,但仍然想使用ComboBox中的DisplayMemberPath,您不需要在样式的Content绑定中放任何东西,因为Parent(ComboBox)会为您解决这个问题。由于DisplayMemberPath只是一个字符串而不是实际的属性,如果您将其绑定到DisplayMemberPath,所有项都将只显示您放入DisplayMemberPath中的任何值。

因此,您只需从ComboBoxItem样式中删除Content绑定即可。

例如:

<Style TargetType="{x:Type ComboBoxItem}">
    .............
    <Border x:Name="ItemBorder" Padding="2,0"  BorderThickness="1"  CornerRadius="3">
        <ContentPresenter /> <!-- no content binding -->
    </Border>

这是一个简单的示例,展示了它的工作原理。
XAML:
<Window x:Class="WpfApplication13.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" x:Name="UI" Width="343" Height="744.625" >
    <Window.Resources>
        <Style TargetType="{x:Type ComboBoxItem}">
            <Setter Property="SnapsToDevicePixels" Value="True" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ComboBoxItem">
                        <Border x:Name="ItemBorder" Padding="2,0"  BorderThickness="1"  CornerRadius="3">
                            <ContentPresenter />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <StackPanel DataContext="{Binding ElementName=UI}">
        <ComboBox ItemsSource="{Binding Items}" DisplayMemberPath="Name" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120"/>
        <ComboBox ItemsSource="{Binding Items}" DisplayMemberPath="State" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120"/>
    </StackPanel>

</Window>

代码:

public partial class MainWindow : Window
{

    public MainWindow() 
    {
        InitializeComponent();

        for (int i = 0; i < 50; i++)
        {
            Items.Add(new ComboBoxModel { Name = "Name" + i, State = "State" + i });
        }
    }

    private ObservableCollection<ComboBoxModel> _items = new ObservableCollection<ComboBoxModel>();
    public ObservableCollection<ComboBoxModel> Items
    {
        get { return _items; }
        set { _items = value; }
    }

}

public class ComboBoxModel
{
    public string Name { get; set; }
    public string State { get; set; }
}

结果:

这里输入图片描述 这里输入图片描述


1
谢谢,你救了我大忙了。我已经试了几个小时了,一直在尝试做同样的事情,但它就是不想工作。直到我将你的解决方案与我的进行比较,并发现有一个小细节不同:我没有为ControlTemplate提供TargetType =“{x:Type ComboBoxItem}”。当我添加了这个之后,突然就看到了内容。之后,我在文档中找到了一个小注释:“还要注意,如果模板定义包含ContentPresenter,则ControlTemplate上需要TargetType属性。”但是在ContentPresenter的文档中没有(尽管在示例中有)。 - Daniel Albuschat

-1

试试这个

<ContentPresenter Content="{TemplateBinding DisplayMemberPath}"/>

不行。你不能这样编译它,因为 DisplayMemberPath 不是 ComboBoxItem 的属性。如果你使用 ComboBox.DisplayMemberPath,下拉框中什么也不会显示。 - Nathanael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接