在WPF ListBox中,如何将项目的焦点选择样式“复制”到非焦点选择样式?

时间:2016-03-09 11:58:18

标签: wpf xaml listbox

首先,Setting the Inactive Highlight Colour of a WPF ListBox to the Active Highlight Colour的副本。对此的解释如下。

环境:

我在UserControl中有一个WPF ListBox,稍后会将其放入使用重量主题的应用程序中。从UserControl的角度来看,我事先并不知道主题是什么样的。

所需行为

如果ListBox在某些时候没有焦点,我仍然希望所选的ListBoxItems具有与ListBox具有焦点时相同的外观。

其他信息:

请注意,仅将颜色设置为某些系统默认值将无效。这样做会覆盖包含应用程序的主题。 (这就是为什么这个问题不是上述链接问题的重复的原因。)

有没有办法实现这一点,例如使用XAML?

编辑:经过一番研究后,我想我想创建一个“默认”ListBoxItem样式的副本(“默认”至少就默认值而言) UserControl的级别,其中Trigger的所有Property="Button.IsFocused" Value="False"都不会被触发,所有带有Trigger的{​​{1}}将始终被触发。

不幸的是,我不知道在哪里开始研究如何实现这一目标。因此,对于我可以开始研究的地方的任何暗示都将非常受欢迎。

1 个答案:

答案 0 :(得分:3)

摘要

您似乎希望将聚焦风格设置为与非聚焦风格相同,而无需编辑主题并以独立于主题的方式进行。据我所知,这是不可能的,主要是因为每个主题在技术上可以以不同的方式实现ListBoxItem焦点行为。事实上,我已经看到了一个主题,其中您期望的行为是ListBoxItem的行为!

如何修改主题

现在,如果您愿意修改每个主题以满足您的需求,请提前阅读。

如果您要全局修改主题,则可以直接编辑ListBoxItem的样式(在找到它存在的位置之后)。如果您希望更具体地应用更改,那么您最终将复制当前的ListBoxItem样式(来自您正在编辑的任何主题)并对其进行更改。

默认ListBoxItem主题的副本如下(我使用Visual Studio进行复制)。你需要改变的事情对于每个主题都会略有不同,但总体思路是一样的。

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

关键部分在中间:

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

这是在聚焦和未聚焦时为所选项目设置两种不同的样式。

要获得您想要的行为,您有以下两种选择之一;您可以将其简单地转换为IsSelected上的简单触发器 ,将以上块替换为:

<Trigger Property="IsSelected" Value="True">
  <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
  <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
</Trigger>

您可以更改Item.SelectedInactive.BackgroundItem.SelectedInactive.Border属性以匹配活动颜色(这高于ListBox样式):

<SolidColorBrush x:Key="Item.SelectedInactive.Background" Color="#3D26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Border" Color="#FF26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Background" Color="#3D26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Border" Color="#FF26A0DA"/>

一般来说,第一种方法是首选,因为它更清楚发生了什么。

附加约束

现在,默认主题ListBoxItem的上述副本将为所有ListBoxItem更改它。如果你只想更改一些,那么你需要为你的“复制样式”添加一个键,如下所示:

<Style x:Key="InactiveLikeActive" TargetType="{x:Type ListBoxItem}">

然后在您想要应用样式的某个级别(甚至可能只是单个ListBox本身),添加以下样式定义:

<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource InactiveLikeActive}" />

例如:

<ListBox>
  <ListBox.Resources>
    <Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource InactiveLikeActive}" />
  </ListBox.Resources>
  <ListBoxItem>One</ListBoxItem>
  <ListBoxItem>Two</ListBoxItem>
</ListBox>

结束思考

虽然WPF可以覆盖几乎所有的默认外观,但它并不一定容易或简单。