设置背景颜色或WPF(4.0) ListBox - Windows 8

21

我正在尝试将选定的ListBoxItem的背景颜色设置为白色,而不是系统颜色。我已经阅读了在此处找到的内容,并已经遵循或认为遵循了那里的建议(更改所选ListBox项的背景颜色WPF如何在列表框失去焦点时更改列表框所选项目文本颜色更改所选和未聚焦的Listbox样式以使其不变灰等)。

所有这些方法似乎都通过将HighlightBrush和ControlBrush设置为所选项目的Transparent来解决问题。 我有以下XAML代码可正确设置字体颜色,但无论刷子设置如何,背景始终是默认的透明蓝色。 我对WPF还不太熟悉,所以我肯定是错过了一些简单的东西。

<ListBox Width="Auto" Height="Auto" Grid.Column="0" BorderThickness="0" Background="#FFF3F3F3" xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <ListBox.ItemsSource>
       <x:Array Type="{x:Type sys:String}">
          <sys:String>String 1</sys:String>
          <sys:String>String 2</sys:String>
          <sys:String>String 3</sys:String>
          <sys:String>String 4</sys:String>
       </x:Array>
    </ListBox.ItemsSource>
    <ListBox.ItemContainerStyle>
       <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
          <Style.Resources>
             <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
             <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
          </Style.Resources>
          <Setter Property="HorizontalContentAlignment" Value="Stretch" />
          <Setter Property="FontSize" Value="16"/>
          <Setter Property="Foreground" Value="#999999"/>
          <Style.Triggers>
             <Trigger Property="IsSelected" Value="True" >
                <Setter Property="Background" Value="White" />
                <Setter Property="Foreground" Value="Black" />
             </Trigger>
          </Style.Triggers>
       </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
       <DataTemplate>
          <TextBlock Text="{Binding}" HorizontalAlignment="Right" Margin="0,0,8,0" Background="Transparent"/>
       </DataTemplate>
    </ListBox.ItemTemplate>
 </ListBox>

我希望能得到任何指引。

编辑:

在阅读第一个答案后,发现有些微小的更改使其在Windows 7虚拟机上运行。这个应用程序在我的Windows 8计算机上开发并执行,它按预期工作。有什么想法可以让它在Windows 8和Windows 7上都能工作?

3个回答

50

这些帖子对于Windows-8已经过时了。

由于某种原因,在Windows-8中,微软不希望人们轻易地编辑他们的默认样式或使用刷子覆盖等功能。

VS 中的 ListBoxItem 默认样式具有以下选择触发器:

<MultiTrigger>
  <MultiTrigger.Conditions>
    <Condition Property="Selector.IsSelectionActive"
                Value="False" />
    <Condition Property="IsSelected"
                Value="True" />
  </MultiTrigger.Conditions>
  <Setter TargetName="Bd"
          Property="Background"
          Value="#3DDADADA" />
  <Setter TargetName="Bd"
          Property="BorderBrush"
          Value="#FFDADADA" />
</MultiTrigger>
<MultiTrigger>
  <MultiTrigger.Conditions>
    <Condition Property="Selector.IsSelectionActive"
                Value="True" />
    <Condition Property="IsSelected"
                Value="True" />
  </MultiTrigger.Conditions>
  <Setter TargetName="Bd"
          Property="Background"
          Value="#3D26A0DA" />
  <Setter TargetName="Bd"
          Property="BorderBrush"
          Value="#FF26A0DA" />
</MultiTrigger>

选择状态触发器现在不再应用于可以轻松覆盖的画笔,而是静态颜色。因此,要修改它,您需要派生模板并在那里修改触发器为White

这是VS2012 Windows-8为ListBoxItem提供的完整样式。

<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 FindAncestor,
                                                         AncestorLevel=1,
                                                         AncestorType={x:Type ItemsControl}}}" />
  <Setter Property="VerticalContentAlignment"
          Value="{Binding VerticalContentAlignment,
                          RelativeSource={RelativeSource FindAncestor,
                                                         AncestorLevel=1,
                                                         AncestorType={x:Type ItemsControl}}}" />
  <Setter Property="Background"
          Value="Transparent" />
  <Setter Property="BorderBrush"
          Value="Transparent" />
  <Setter Property="BorderThickness"
          Value="1" />
  <Setter Property="FocusVisualStyle">
    <Setter.Value>
      <Style>
        <Setter Property="Control.Template">
          <Setter.Value>
            <ControlTemplate>
              <Rectangle Margin="2"
                         SnapsToDevicePixels="True"
                         Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
                         StrokeDashArray="1 2"
                         StrokeThickness="1" />
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </Setter.Value>
  </Setter>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ListBoxItem}">
        <Border x:Name="Bd"
                Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                Padding="{TemplateBinding Padding}"
                SnapsToDevicePixels="True">
          <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            Content="{TemplateBinding Content}"
                            ContentStringFormat="{TemplateBinding ContentStringFormat}"
                            ContentTemplate="{TemplateBinding ContentTemplate}"
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
        </Border>
        <ControlTemplate.Triggers>
          <MultiTrigger>
            <MultiTrigger.Conditions>
              <Condition Property="IsMouseOver"
                         Value="True" />
            </MultiTrigger.Conditions>
            <Setter TargetName="Bd"
                    Property="Background"
                    Value="#1F26A0DA" />
            <Setter TargetName="Bd"
                    Property="BorderBrush"
                    Value="#A826A0DA" />
          </MultiTrigger>
          <MultiTrigger>
            <MultiTrigger.Conditions>
              <Condition Property="Selector.IsSelectionActive"
                         Value="False" />
              <Condition Property="IsSelected"
                         Value="True" />
            </MultiTrigger.Conditions>
            <Setter TargetName="Bd"
                    Property="Background"
                    Value="#3DDADADA" />
            <Setter TargetName="Bd"
                    Property="BorderBrush"
                    Value="#FFDADADA" />
          </MultiTrigger>
          <MultiTrigger>
            <MultiTrigger.Conditions>
              <Condition Property="Selector.IsSelectionActive"
                         Value="True" />
              <Condition Property="IsSelected"
                         Value="True" />
            </MultiTrigger.Conditions>
            <Setter TargetName="Bd"
                    Property="Background"
                    Value="#3D26A0DA" />
            <Setter TargetName="Bd"
                    Property="BorderBrush"
                    Value="#FF26A0DA" />
          </MultiTrigger>
          <Trigger Property="IsEnabled"
                   Value="False">
            <Setter TargetName="Bd"
                    Property="TextElement.Foreground"
                    Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

如果您修改这些触发器为:

<MultiTrigger>
  <MultiTrigger.Conditions>
    <Condition Property="Selector.IsSelectionActive"
                Value="False" />
    <Condition Property="IsSelected"
                Value="True" />
  </MultiTrigger.Conditions>
  <Setter TargetName="Bd"
          Property="Background"
          Value="White" />
  <Setter TargetName="Bd"
          Property="BorderBrush"
          Value="White" />
</MultiTrigger>
<MultiTrigger>
  <MultiTrigger.Conditions>
    <Condition Property="Selector.IsSelectionActive"
                Value="True" />
    <Condition Property="IsSelected"
                Value="True" />
  </MultiTrigger.Conditions>
  <Setter TargetName="Bd"
          Property="Background"
          Value="White" />
  <Setter TargetName="Bd"
          Property="BorderBrush"
          Value="White" />
</MultiTrigger>

你应该解决了你的问题。


1
@RobGoodwin 没问题。你可以从 https://www.dropbox.com/s/4ni0dbcgzji5h8n/ListBoxSelectionWin8.rar 下载我为你的问题准备的示例,以查看样式覆盖。 - Viv
那个有效。感谢您抽出时间发布样例。它让我能够快速在Windows 7和8上进行测试。并且它为我提供了更多关于WPF控件样式的学习来源。 - Rob Goodwin
1
@DefenestrationDay 不确定你的意思是什么。答案中提到的“这个方法”只是你用自定义画笔指定的Style,而不是默认的画笔。AlternationCount是一个属性,你仍然可以在ListBox上设置它,并且如果你有一个触发器,比如<Trigger Property="ListBox.AlternationIndex" Value="0"><Setter Property="Foreground" Value="Tomato" /></Trigger><ControlTemplate.Triggers>Style中,你会看到具有索引0作为AlternationIndex的项目的Foreground成功切换为Tomato - Viv
谢谢!我一度以为自己疯了! - Jammer
非常感谢!我已经花了很长时间在这个问题上,没有意识到大多数解决方案只适用于Windows 7。 - Freek Sanders
显示剩余2条评论

10
将以下触发器添加到我的项数据模板中,适用于Windows 10:
<DataTemplate x:Key="MyItemTemplate">
    <Border Name="Border" Background="Transparent" BorderBrush="LightGray" BorderThickness="0,1,0,0" Padding="0">
        <TextBlock Text="{Binding Text}" HorizontalAlignment="Left" FontWeight="Medium" />
    </Border>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">
            <Setter TargetName="Border" Property="Background" Value="SkyBlue"/>
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

3
最干净,最简洁的解决方案适用于Windows 8! - RDV
1
我希望我能够给更多的赞。比上面那些粗糙的解决方案好多了! - Indigo
一个不错的解决方法。然而,在我的情况下(截至2023年3月,使用Win 10),浅蓝色的选择矩形仍然可见,但它大部分被一个稍小的带有自己颜色的矩形覆盖。两者一起看起来像是一个小的浅蓝色框架围绕着我自己的彩色矩形。这个“框架”随着边距的增加而增加,而我使用了相当大的边距,所以看起来非常丑陋。 - Tobias Knauss

0

所以你只是想让选定项的背景变成白色吗?

除了 ControlBrushKey 设置之外,你的代码对我来说都有效:

<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="White" />
</Style.Resources>

有趣的是,阅读完这篇文章后,我将我的应用程序移植到了一个Windows 7系统上,它按预期工作。但在我的Windows 8机器上却不行。 - Rob Goodwin
没错,在Windows .Net 4.5之前这个方法很好用。但由于某些不可理喻的原因,触发器的值从系统画刷变成了硬编码颜色值和动态资源。因此,像那样覆盖这些资源将不再影响ListBox。我猜其他控件的情况也类似,但目前我只在ListBox上验证过。 - MojoFilter

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