ComboBox 的自定义模板忽略 DisplayMemberPath 的使用

发布于 2024-12-13 18:28:59 字数 7487 浏览 9 评论 0原文

所以我在网站上浏览了几个问题,但似乎找不到答案。

我有一个ComboBox。它工作得很好。我决定需要彻底修改外观,因此我创建了默认 ComboBox 模板的副本(这是直接副本,没有修改):

<ControlTemplate x:Key="ComboBoxControlTemplate2" TargetType="{x:Type ComboBox}">
            <Grid x:Name="MainGrid" SnapsToDevicePixels="True">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
                </Grid.ColumnDefinitions>
                <Popup x:Name="PART_Popup" AllowsTransparency="True" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                    <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}">
                        <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                            <ScrollViewer x:Name="DropDownScrollViewer">
                                <Grid RenderOptions.ClearTypeHint="Enabled">
                                    <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                        <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                                    </Canvas>
                                    <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                </Grid>
                            </ScrollViewer>
                        </Border>
                    </Microsoft_Windows_Themes:SystemDropShadowChrome>
                </Popup>
                <ToggleButton BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
                    <ToggleButton.Style>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="OverridesDefaultStyle" Value="True"/>
                            <Setter Property="IsTabStop" Value="False"/>
                            <Setter Property="Focusable" Value="False"/>
                            <Setter Property="ClickMode" Value="Press"/>
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" SnapsToDevicePixels="True">
                                            <Grid HorizontalAlignment="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
                                                <Path x:Name="Arrow" Data="M0,0L3.5,4 7,0z" Fill="Black" HorizontalAlignment="Center" Margin="3,1,0,0" VerticalAlignment="Center"/>
                                            </Grid>
                                        </Microsoft_Windows_Themes:ButtonChrome>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="RenderPressed" TargetName="Chrome" Value="True"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Fill" TargetName="Arrow" Value="#FFAFAFAF"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToggleButton.Style>
                </ToggleButton>
                <ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="False" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="True">
                    <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
                    <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
                </Trigger>
                <Trigger Property="HasItems" Value="False">
                    <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    <Setter Property="Background" Value="#FFF4F4F4"/>
                </Trigger>
                <Trigger Property="IsGrouping" Value="True">
                    <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                </Trigger>
                <Trigger Property="CanContentScroll" SourceName="DropDownScrollViewer" Value="False">
                    <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
                    <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

现在,当我从列表中选择一个项目(这是 POCO 的集合)时,它是显示名称空间和类名而不是它应该显示的值。

我的研究和实验使我相信问题在于我的新模板没有使用 DisplayMemberPath 属性。我尝试通过重写 OnDisplayMemberPathChanged 方法来设置 ItemTemplate,但是当我从列表中选择项目时,会导致错误。

我还看到人们通过 XAML 设置 ItemTemplate,但我有数百个组合框,但我不想这样做。

是否有某种方法可以利用我的 ControlTemplate 中的 DisplayMemberPath 属性,或者我可以在派生控件中运行一些代码来实现我想要的结果?

So I've gone through several questions on the site, and I cannot seem to find the answer.

I have a ComboBox. It was working just fine. I decide I need to overhaul the appearance, so I create a copy of the default ComboBox template (this is a straight copy, no modifications):

<ControlTemplate x:Key="ComboBoxControlTemplate2" TargetType="{x:Type ComboBox}">
            <Grid x:Name="MainGrid" SnapsToDevicePixels="True">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
                </Grid.ColumnDefinitions>
                <Popup x:Name="PART_Popup" AllowsTransparency="True" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                    <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}">
                        <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                            <ScrollViewer x:Name="DropDownScrollViewer">
                                <Grid RenderOptions.ClearTypeHint="Enabled">
                                    <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                        <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                                    </Canvas>
                                    <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                </Grid>
                            </ScrollViewer>
                        </Border>
                    </Microsoft_Windows_Themes:SystemDropShadowChrome>
                </Popup>
                <ToggleButton BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
                    <ToggleButton.Style>
                        <Style TargetType="{x:Type ToggleButton}">
                            <Setter Property="OverridesDefaultStyle" Value="True"/>
                            <Setter Property="IsTabStop" Value="False"/>
                            <Setter Property="Focusable" Value="False"/>
                            <Setter Property="ClickMode" Value="Press"/>
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                                        <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" SnapsToDevicePixels="True">
                                            <Grid HorizontalAlignment="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
                                                <Path x:Name="Arrow" Data="M0,0L3.5,4 7,0z" Fill="Black" HorizontalAlignment="Center" Margin="3,1,0,0" VerticalAlignment="Center"/>
                                            </Grid>
                                        </Microsoft_Windows_Themes:ButtonChrome>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsChecked" Value="True">
                                                <Setter Property="RenderPressed" TargetName="Chrome" Value="True"/>
                                            </Trigger>
                                            <Trigger Property="IsEnabled" Value="False">
                                                <Setter Property="Fill" TargetName="Arrow" Value="#FFAFAFAF"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToggleButton.Style>
                </ToggleButton>
                <ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="False" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="True">
                    <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
                    <Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
                </Trigger>
                <Trigger Property="HasItems" Value="False">
                    <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    <Setter Property="Background" Value="#FFF4F4F4"/>
                </Trigger>
                <Trigger Property="IsGrouping" Value="True">
                    <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                </Trigger>
                <Trigger Property="CanContentScroll" SourceName="DropDownScrollViewer" Value="False">
                    <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}"/>
                    <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

Now, when I select an item from my list (which is a collection of POCOs), it's display the namespace and class name instead of the value it's supposed to.

My research and experimentation have led me to believe that the problem is that my new template does not make use of the DisplayMemberPath property. I tried to set an ItemTemplate by overriding the OnDisplayMemberPathChanged method, but that results in errors when I select an item from the list.

I have also seen people set the ItemTemplate via XAML, but I have hundreds of comboboxes, and I don't want to do that.

Is there some way to utilize the DisplayMemberPath property in my ControlTemplate, or some code I could run in a derived control to achieve my desired result?

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

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

发布评论

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

评论(5

-小熊_ 2024-12-20 18:29:00

我有同样的问题,事实证明设置 DisplayMemberPath 只是一种快捷方式将 ItemTemplate 设置为包含该值的 TextBlock

因此,当您设置 ItemTemplate 时,DisplayMemberPath 将变得无用,因为您已使用默认 TextBlock 添加的值覆盖了它。

I had the same question, and it turns out setting the DisplayMemberPath is simply a shortcut way for setting the ItemTemplate to a TextBlock with that value in it.

Because of this, when you set the ItemTemplate then DisplayMemberPath becomes useless because you have overwritten the default TextBlock with value that it adds.

神经暖 2024-12-20 18:29:00

我遇到了同样的问题,这应该是一个错误,我会尝试报告它。

当您从 Visual Studio 中“编辑控件模板的副本”时,它会错过以下行:

ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

这导致“DisplayMemberPath”无法正常工作。

I met the same issue, this should be a bug, I'll try report it.

When you "edit a copy" of the control template from Visual Studio, it misses the line:

ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

Which caused "DisplayMemberPath" not working properly.

剧终人散尽 2024-12-20 18:29:00

我知道这是一个老问题,但这些天我遇到了同样的问题,我修复了它,添加

ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"

而不是

ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

I know this is an old question, but I faced the same problem in these days and I fixed it adding

ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"

instead of

ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

仅冇旳回忆 2024-12-20 18:28:59

这不是一个精确的副本,此元素中缺少一个关键的东西:

<ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
        Content="{TemplateBinding SelectionBoxItem}"
        ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}"
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        IsHitTestVisible="False"
        Margin="{TemplateBinding Padding}"
        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />

也许您不小心删除了它,即:

 ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

如果您没有此设置,则 DisplayMemberPath 将无法工作因为 ComboBox 使用模板选择器在模板之间进行选择(您可以使用 ItemTemplateDisplayMemberPath)。

That is not an exact copy, one crucial thing is missing in this element:

<ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
        Content="{TemplateBinding SelectionBoxItem}"
        ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}"
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        IsHitTestVisible="False"
        Margin="{TemplateBinding Padding}"
        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />

Maybe you accidentally deleted it, namely:

 ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

If you do not have this set the DisplayMemberPath will not work because the ComboBox selects between templates using a template selector (as you can use ItemTemplate or DisplayMemberPath).

朱染 2024-12-20 18:28:59

确保您没有丢失 ContentTemplateSelector 元素。

对于组合框模板本身,它应该是:

ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

对于 ItemsContainerStyle 它应该是:

ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"        

Make sure you are not missing the ContentTemplateSelector elements.

For the combox template itself it should be:

ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"

For the ItemsContainerStyle it should be:

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