You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何ListBox的ItemContainerStyle会使ItemTemplateSelector失效?

问题:ListBoxItem的ItemContainerStyle导致ItemTemplateSelector失效

我在.NET 6.0 WPF应用中定义了一个ListBoxItem的ItemContainerStyle,此前单独在ListBox上使用时一切正常。但当给ListBox同时设置ItemTemplateSelector属性后,发现ItemTemplateSelector完全被忽略:调试输出窗口无任何警告或错误,SelectTemplate方法从未被调用,ListBox最终仅显示项的类名文本。移除ItemContainerStyle后,ItemTemplateSelector恢复正常,SelectTemplate会为每个项执行,但此时ListBoxItem的样式不符合预期。

以下是我使用的ItemContainerStyle代码:

<Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Padding"                     Value="3,0,3,0" />
    <Setter Property="HorizontalContentAlignment"  Value="Stretch" />
    <Setter Property="VerticalContentAlignment"    Value="Top" />
    <Setter Property="Background"                  Value="Transparent" />
    <Setter Property="BorderBrush"                 Value="Transparent" />
    <Setter Property="BorderThickness"             Value="1" />
    <Setter Property="SnapsToDevicePixels"         Value="True" />
    <Setter Property="Foreground"                  Value="{StaticResource GsForegroundLight}" />
    <Setter Property="KeyboardNavigation.TabNavigation" Value="Local" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Grid>
                    <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        CornerRadius="1"
                        SnapsToDevicePixels="True" />

                    <!--  MouseOver Visual is exactly like Selected Visual (below) minus the rounded corners  -->

                    <Border
                        x:Name="MouseOverVisual"
                        BorderBrush="{StaticResource GsForegroundLight}"
                        BorderThickness="1"
                        CornerRadius="3"
                        Opacity="0"
                        SnapsToDevicePixels="True">
                        <Border BorderThickness="1" CornerRadius="3" SnapsToDevicePixels="True">
                            <Border.Background>
                                <LinearGradientBrush Opacity="0.5" StartPoint="0.5,0" EndPoint="0.5,1">
                                    <GradientStop Offset="1" Color="{StaticResource GsBackgroundDarkColor}" />
                                    <GradientStop Color="Gray" />
                                </LinearGradientBrush>
                            </Border.Background>
                        </Border>
                    </Border>

                    <!--  Selected Visual uses no border but just a gradient background brush  -->

                    <Border x:Name="SelectedVisual"
                        BorderThickness="0"
                        CornerRadius="3"
                        Opacity="0"
                        SnapsToDevicePixels="True">
                        <Border
                            BorderBrush="Black"
                            BorderThickness="1"
                            CornerRadius="3"
                            SnapsToDevicePixels="True">
                            <Border.Background>
                                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                    <GradientStop Offset="1" Color="{StaticResource GsBackgroundDarkColor}" />
                                    <GradientStop Color="Gray" />
                                </LinearGradientBrush>
                            </Border.Background>
                        </Border>
                    </Border>
                    <ContentPresenter x:Name="contentPresenter"
                        Margin="{TemplateBinding Padding}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                        Content="{TemplateBinding Content}"
                        ContentStringFormat="{TemplateBinding ContentStringFormat}"
                        ContentTemplate="{TemplateBinding ContentTemplate}" />

                    <!--  JMO: Removed the focus visual altogether by setting border thickness to zero  -->
                    <Border  x:Name="FocusVisual"
                        BorderBrush="#FFFFC92B"
                        BorderThickness="0"
                        CornerRadius="1"
                        Opacity="0"
                        SnapsToDevicePixels="True" />
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetName="MouseOverVisual"
                                        Storyboard.TargetProperty="Opacity"
                                        To="1"
                                        Duration="0" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetName="contentPresenter"
                                        Storyboard.TargetProperty="Opacity"
                                        To="0.5"
                                        Duration="0" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetName="SelectedVisual"
                                        Storyboard.TargetProperty="Opacity"
                                        To="1"
                                        Duration="0" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused">
                                <Storyboard>
                                    <DoubleAnimation
                                        Storyboard.TargetName="FocusVisual"
                                        Storyboard.TargetProperty="Opacity"
                                        To="1"
                                        Duration="0" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unfocused" />
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>  

问题原因

问题出在自定义ControlTemplate内的ContentPresenter上:你只绑定了ContentTemplate属性,但没有绑定ContentTemplateSelector。当ListBox通过ItemTemplateSelector为项选择模板时,这个选择器是传递给ListBoxItem的ContentTemplateSelector属性,而非直接设置ContentTemplate。由于你的ContentPresenter没有响应这个Selector,无法应用选中的模板,最终只能显示对象的ToString()结果(即类名)。

修复方案

修改ControlTemplate中的ContentPresenter,添加ContentTemplateSelector的模板绑定,完整代码如下:

<ContentPresenter x:Name="contentPresenter"
    Margin="{TemplateBinding Padding}"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Content="{TemplateBinding Content}"
    ContentStringFormat="{TemplateBinding ContentStringFormat}"
    ContentTemplate="{TemplateBinding ContentTemplate}"
    ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}" />

修改后,ItemContainerStyle和ItemTemplateSelector即可同时正常工作:ListBoxItem会应用你的自定义样式,同时每个项会通过ItemTemplateSelector选择对应的模板进行渲染。

内容的提问来源于stack exchange,提问作者Joe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 08:10:29