【问题标题】:WPF ListBox Highlight in Windows 10Windows 10 中的 WPF 列表框突出显示
【发布时间】:2016-03-04 19:47:48
【问题描述】:

我对 WPF 相当陌生,但在 .NET (Winforms) 方面经验丰富。我正在尝试操纵列表框的突出显示样式来控制所选项目的聚焦和未聚焦颜色。我发现的每个教程都使用自定义样式为 SystemColors.HighlightBrushKey 和 SystemColors.ControlBrushKey 分配新值。但它不起作用。经过无数小时试图让它工作,我突然想到它可能与操作系统有关。我一直在 Windows 10 系统上尝试它。我在 Windows 7 设置上运行了完全相同的代码,你瞧,它成功了!

显然旧方法在 Windows 10 中不起作用(至少在我看来是这样)。有没有人找到替代方案?归根结底,我只希望列表框即使在没有焦点的情况下也能保持明亮的高光。默认的灰色高亮很难看到,并且在某些用法中似乎不合适。我有一个真实的场景,当焦点从 ListBox 移开时,高光基本上消失了,感觉非常不自然。

下面是我在 Windows 7 上使用但在 Windows 10 上无法使用的 XAML 代码。(顺便说一下,我也尝试将 SystemColors.ControlBrushKey 替换为 SystemColors.InactiveSelectionHighlightBrushKey - 结果相同)。

    <Window x:Class="TestApp.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestApp"
        mc:Ignorable="d"
        Title="TestWindow" Height="300" Width="300" Loaded="Window_Loaded">
    <Window.Resources>
        <Style x:Key="myListboxStyle">
            <Style.Resources>
                <!-- Background of selected item when focused -->
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red" />
                <!-- Background of selected item when not focused -->
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Green" />
            </Style.Resources>
        </Style>
    </Window.Resources>
    <Grid>
        <ListBox x:Name="listBox" Style="{StaticResource myListboxStyle}" HorizontalAlignment="Left" Height="100" Margin="22,18,0,0" VerticalAlignment="Top" Width="237">
            <ListBoxItem>Test 1</ListBoxItem>
            <ListBoxItem>Test 2</ListBoxItem>
            <ListBoxItem>Test 3</ListBoxItem>
        </ListBox>
            <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="50,165,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>

    </Grid>
</Window>

【问题讨论】:

标签: wpf xaml listbox windows-10


【解决方案1】:

微软在 Windows 10 上打破了这个问题,但我们可以修复它!

这是模板在 Windows 10 中的样子(只是我关心的部分):

   <ControlTemplate TargetType="{x:Type ListBoxItem}">
 ...
        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
            <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Border>
        <ControlTemplate.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsMouseOver" Value="True"/>
                </MultiTrigger.Conditions>
                <Setter Property="Background" TargetName="Bd" Value="#1F26A0DA"/>
                <Setter Property="BorderBrush" TargetName="Bd" Value="#A826A0DA"/>
            </MultiTrigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="Selector.IsSelectionActive" Value="False"/>
                    <Condition Property="IsSelected" Value="True"/>
                </MultiTrigger.Conditions>
                <Setter Property="Background" TargetName="Bd" Value="#3DDADADA"/>
                <Setter Property="BorderBrush" TargetName="Bd" Value="#FFDADADA"/>
            </MultiTrigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="Selector.IsSelectionActive" Value="True"/>
                    <Condition Property="IsSelected" Value="True"/>
                </MultiTrigger.Conditions>
                <Setter Property="Background" TargetName="Bd" Value="#3D26A0DA"/>
                <Setter Property="BorderBrush" TargetName="Bd" Value="#FF26A0DA"/>
            </MultiTrigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

请注意,他们已经对颜色值进行了硬编码,例如“#1F26A0DA”。

在 Windows 7 中,ListBoxItems 的内置模板是:

         <ControlTemplate TargetType="{x:Type ListBoxItem}">
...
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="true"/>
                                <Condition Property="Selector.IsSelectionActive" Value="false"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
          </ControlTemplate>

所以基本上微软在 Windows 7 中使用了诸如“SystemColors.InactiveSelectionHighlightBrushKey”之类的资源。但现在他们做到了,所以我们不能在不覆盖模板的情况下这样做;因为它们在所有值中都进行了硬编码。

因此,要修补此问题,只需在 App.Xaml 文件中覆盖 ListBoxItem 的模板;让一切都得到补丁。

 <Style TargetType="{x:Type ListBoxItem}">
        <Style.Resources> <!-- Use your own colors here if you want, or do it per class -->    
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FFFFA500"/> 
            <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey }" Color="#FFFFA500"/>
        </Style.Resources>

      <Setter Property="Template">
<!-- Revert the Template in Windows 10 to match the Windows 7 template that used "SystemColors.HighlightBrushKey" and such-->
                <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="true"/>
                                <Condition Property="Selector.IsSelectionActive" Value="false"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>

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

【讨论】:

  • 感谢建设性的回答,我会为这件事把微软推向无止境的。他们不仅有效地将 WPF 变成了具有此平台差异的 IE6,而且完全破坏了主题支持。这么多年来一直如此的事实只是告诉我们 WPF 已经变得多么边缘化。新的VB6差不多。
【解决方案2】:

如果您真的想更改应用的默认设置,您可以随时通过复制模板来修改样式。在本例中为 ListBoxItem 样式。

在设计器中,单击 ListBoxItem,右键单击编辑模板,然后编辑副本。

以下是我在我的机器上获得的内容,以及以红色/绿色运行的应用程序的屏幕截图,展示了应用于受影响项目的样式。您当然会将其应用于所有项目...

<Window.Resources>
    <Style x:Key="FocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <SolidColorBrush x:Key="Item.MouseOver.Background" Color="#1F26A0DA"/>
    <SolidColorBrush x:Key="Item.MouseOver.Border" Color="#a826A0Da"/>
    <SolidColorBrush x:Key="Item.SelectedInactive.Background" Color="#3DDADADA"/>
    <SolidColorBrush x:Key="Item.SelectedInactive.Border" Color="#FFDADADA"/>
    <SolidColorBrush x:Key="Item.SelectedActive.Background" Color="#3D26A0DA"/>
    <SolidColorBrush x:Key="Item.SelectedActive.Border" Color="#FF26A0DA"/>
    <Style x:Key="ListBoxItemStyle1" TargetType="{x:Type ListBoxItem}">
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="Padding" Value="4,1"/>
        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.MouseOver.Background}"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.MouseOver.Border}"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="False"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Background}"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Border}"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="True"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="ListBoxItemStyle2" TargetType="{x:Type ListBoxItem}">
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="Padding" Value="4,1"/>
        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.MouseOver.Background}"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.MouseOver.Border}"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="False"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="Red"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Border}"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="True"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="Green"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</Window.Resources>

<Grid x:Name="LayoutRoot" Opacity="{Binding MainWindowOpacity}">
    <StackPanel>
        <TextBlock Text="WPF" FontSize="36" Margin="20" Foreground="Orange" HorizontalAlignment="Center"/>
        <ListBox x:Name="listBox" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="237">
            <ListBoxItem Style="{DynamicResource ListBoxItemStyle1}">Test 1</ListBoxItem>
            <ListBoxItem Style="{DynamicResource ListBoxItemStyle2}">Test 2</ListBoxItem>
            <ListBoxItem>Test 3</ListBoxItem>
        </ListBox>
    </StackPanel>
</Grid>

以及正在运行的应用程序:

活动:

不活跃:

告诫购买者。

【讨论】:

  • 谢谢科里。我已经在使用类似于您的解决方案(我以前使用过类似的东西来自定义 TreeView 的外观),但是您的指示给了我缺少的部分来获得我想要的东西。
  • 这对我有用,令人失望的是在 Windows 10 中需要这么多才能工作......
【解决方案3】:

我在 Windows 10 下对 ListBoxes 的突出显示样式有类似的问题...同样,旧的 SystemColors.HighlightBrushKey 和 SystemColors.ControlBrushKey 解决方案仅在 Windows 7 下对我有效。就我而言,我只是想 完全删除任何 WPF 绘制的突出显示,所以我可以用我自己的替换它。

为此,我只是通过资源中的以下简短样式替换了 ControlTemplate:

        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

我通常不喜欢替换冗长的 ControlTemplates,但这对我来说是一个很好的简洁解决方案,希望它可以帮助其他人。

【讨论】:

    【解决方案4】:

    恐怕我没有办法专门在 Windows 10 中对此进行测试,但我在 Windows 7 上遇到了类似的问题。在资源中定义“ControlBrushKey”不起作用。

    设置“InactiveSelectionHighlightBrushKey”对我有用:

    <ListBox.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="DodgerBlue" />
    </ListBox.Resources>
    

    道奇蓝与默认的 Aero 选择非常接近;只是头发变黑了。我仍在研究如何将其映射到实际选择值而不是特定颜色。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-21
      • 2010-12-07
      • 2011-03-29
      • 1970-01-01
      • 2019-01-11
      • 1970-01-01
      • 2012-04-25
      相关资源
      最近更新 更多