【问题标题】:Changing The Background Of SelectedItem In WPF ListBox更改 WPF ListBox 中 SelectedItem 的背景
【发布时间】:2020-10-14 20:36:58
【问题描述】:

这个问题已经在这里被问和回答了大约十几次,但给定的答案似乎都不起作用。问题:在 WPF ListBox 中,如何更改(所选项目和/或“鼠标悬停”项目的)突出显示颜色?

这不起作用(根据here) - 突出显示保持默认:

<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="ListBoxSelectedItemsStyle" TargetType="{x:Type ListBoxItem}">
            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Black" />
            </Style.Resources>
        </Style>
    </StackPanel.Resources>
    <ListBox ItemContainerStyle="{StaticResource ListBoxSelectedItemsStyle}">
        <ListBoxItem>Item1</ListBoxItem>
        <ListBoxItem>Item2</ListBoxItem>
        <ListBoxItem>Item3</ListBoxItem>
    </ListBox>
</StackPanel>

这也不起作用(根据here 略有不同):

<StackPanel>
    <ListBox>
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Style.Resources>
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Yellow"/>
                </Style.Resources>
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBoxItem>Item1</ListBoxItem>
        <ListBoxItem>Item2</ListBoxItem>
        <ListBoxItem>Item3</ListBoxItem>
    </ListBox>
</StackPanel>

这也不起作用(根据here):

<StackPanel>
    <ListBox>
        <ListBox.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Black"/>
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Black"/>
            <Style TargetType="{x:Type ListBoxItem}">
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Background" Value="Black"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ListBox.Resources>
        <ListBoxItem>Item1</ListBoxItem>
        <ListBoxItem>Item2</ListBoxItem>
        <ListBoxItem>Item3</ListBoxItem>
    </ListBox>
</StackPanel>

许多答案都包含一些变体(即here 等) - 但无论我使用哪个,都没有任何变化。突出显示不受影响。

【问题讨论】:

  • 有趣。那更近了——我确实看到了黄色背景——但它搞砸了项目的其他方面(即现在它们居中而不是左对齐,它们没有填满宽度等)。所以它似乎改变的不仅仅是背景。
  • 不适合我.....
  • 默认情况下,高亮和可点击区域占据列表框的整个宽度。这样,它只会突出显示文本本身,并且您只能在文本上单击鼠标右键,从而使单击区域明显变小并且项目的功能行为不标准。这不是它为你做的吗?如果不清楚,我可以发布比较屏幕截图...
  • 如前所述,对我来说很好。当然只有 ItemContainerStyle,而不是 XAML 的其余部分。

标签: wpf xaml


【解决方案1】:

您尝试的所有三个版本基本上是相同的:它们提供了一个新资源,使用默认 ListBoxItem 控件模板使用的相同键。理论上,通过提供具有相同键的新资源项,当框架需要寻找合适的资源时,它会遍历加载的资源字典,首先找到你的,然后使用它而不是原来的默认。

但似乎有几个问题:

  • 首先,自从提供了这些引用后,所使用的密钥发生了变化。当我查看当前的ListBoxItem 样式时,它使用常规字符串作为键,而不是SystemColors 类中的这些属性。当前键名是"Item.SelectedActive.Background",用于设置项目被选中并获得焦点时的背景。
  • 其次,即使使用新密钥,我也无法找到并使用资源项。原来的默认画笔仍在使用中,尽管理论上是合理的。

可能还有一些方法可以让它继续工作。但是弄清楚这一点需要时间,单步调试调试器中的代码并观察 WPF 在控件初始化和触发器触发时正在做什么。这样的调查可能会揭示 WPF 如何查找资源,以及如何设法使您自己的具有相同密钥的资源被找到。

但目前,我没有时间做所有这些。而且我确实知道如何通过蛮力使其工作。 XAML 工具箱中最大的锤子之一是 XAML 设计器中的 “编辑模板” 命令。为此,您需要创建ListBoxItem 模板的副本,以便您可以使用该模板的编辑版本。在 XAML 编辑器中的设计模式下右键单击 ListBox 并转到此菜单:

选择“编辑副本...”菜单项。

这将为您的文件添加如下所示的新资源:

<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>

它还将更新 XAML 中的 ListBox 以引用项目容器模板的该样式。此时,您可以根据自己的喜好编辑资源。例如,更改"Item.SelectedActive.Background" 键的画笔:

<SolidColorBrush x:Key="Item.SelectedActive.Background" Color="Black"/>

鉴于 WPF 文档确实讨论了资源层次结构以及如何通过密钥找到资源,看起来应该可以在不完全覆盖这样的项目容器样式的情况下使其工作。但目前我不知道该怎么做。

对于它的价值,以上基本上是Changing WPF Listbox SelectedItem text color and highlight/background Color using C# 中提出的内容,减去该问题中发现的所有额外细节。从某种意义上说,这个问题可以被认为是那个问题的重复。

如果您经常遇到这些问题并且想要一个不那么混乱的解决方案,那么您可能会发现一些其他问题。特别是,您可以使用标记扩展来自定义样式的处理方式,从而允许您在 编译 时合并或以其他方式操作资源字典。这是一种更复杂的方法,但如果在您的项目中经常出现这种情况,它可能是值得的。参见例如: XAML Combine Styles How to apply multiple styles in WPF 您的问题确实不是其中任何一个的重复,但基本技术无论如何都可以应用于您的情况。

【讨论】:

  • 完美答案,谢谢!!令人难以置信的令人沮丧的是,显然微软自己完全打破了过去的工作方式,从而使 99% 的答案无效(我花了几个小时尝试解决方案,但没有一个像描述的那样有效)。这有点难看,但至少它是功能性的。我想我应该就答案不再有效的其他一些问题发表一些注释......
  • 是的,我不明白这样的东西怎么会坏。就此而言,我仍然不明白为什么仍然使用相同的技术但使用不同的资源密钥是不够的。假设我没有忽略一些愚蠢的事情(总是可能的),显然现在处理控制模板的方式有些问题,例如资源要么在流程的早期检索,要么从不同的上下文中检索。无论哪种方式,它都会破坏框架中一个不错的架构特性。 :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 2018-03-30
  • 1970-01-01
相关资源
最近更新 更多