全局更改所有控件的鼠标悬停颜色WPF

时间:2020-05-27 23:42:14

标签: c# wpf

将鼠标悬停在按钮,列标题,组合框等上时,它们都会变成漂亮的Microsoft蓝色。

我宁愿他们为我的企业绿色树立漂亮的阴影。

Screenshot

有没有办法针对我的应用程序或按窗口全局更改此颜色。

如果失败,我是否需要针对每种控件类型进行更改?

2 个答案:

答案 0 :(得分:1)

您必须为每个控件定义一个Style。这是因为视觉效果和视觉状态是由每个控件的内部ControlTemplate定义的。

但是您可以通过重用模板和级联样式来显着减少工作量。

要允许轻松进行颜色主题设置和集中式自定义,您应该创建一个资源来定义主题的所有相关颜色:

ColorResources.xaml

<ResourceDictionary>

  <!-- Colors -->
  <Color x:Key="HighlightColor">DarkOrange</Color>
  <Color x:Key="DefaultControlColor">LightSeaGreen</Color>
  <Color x:Key="ControlDisabledTextColor">Gray</Color>
  <Color x:Key="BorderColor">DarkGray</Color>
  <Color x:Key="MouseOverColor">LightSteelBlue</Color>

  <!-- Brushes -->
  <SolidColorBrush x:Key="HighlightBrush" Color="{StaticResource HighlightColor}" />
  <SolidColorBrush x:Key="ControlDisabledTextBrush" Color="{StaticResource ControlDisabledColor}" />
  <SolidColorBrush x:Key="BorderBrush" Color="{StaticResource BorderColor}" />
  <SolidColorBrush x:Key="MouseOverBrush" Color="{StaticResource MouseOverColor}" />
</ResourceDictionary>

您可以将以下样式的模板添加到 App.xaml 文件:

App.xaml

<Application>
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/File/Path/To/ColorResources.xaml" />
      </ResourceDictionary.MergedDictionaries>

      ...
    </ResourceDictionary>
  </Application.Resources>
</Application>

要覆盖GridViewDataGrid中所选行的颜色,您只需要覆盖这些控件使用的默认画笔SystemColors.HighlightBrush

<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" 
                 Color="{StaticResource HighlightColor}" />

要覆盖控件的默认颜色,例如DatGrid的列标题,您只需覆盖这些控件使用的默认画笔SystemColors.ControlBrush

<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" 
                 Color="{StaticResource DefaultControlColor}" />

对于像ContentControlsButton这样的简单ListBoxItem,您可以共享一个公用的ControlTemplate。共享的ControlTemplate将协调视觉状态:

<ControlTemplate x:Key="BaseContentControlTemplate" 
                 TargetType="ContentControl">
  <Border BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}"
          Background="{TemplateBinding Background}">
    <ContentPresenter/>
  </Border>

  <ControlTemplate.Triggers>
    <Trigger Property="IsEnabled" Value="False">
      <Setter Property="Foreground" Value="{StaticResource ControlDisabledTextBrush}" />
    </Trigger>
    <Trigger Property="IsMouseOver" Value="True">
      <Setter Property="Opacity" Value="0.7" />
      <Setter Property="Background" Value="{StaticResource MouseOverBrush}" />
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

此基本模板将使用基本样式应用。这样可以进行简单的链接(样式继承),并可以将BaseContentControlTemplate重用于ButtonListBoxItem等不同的控件:

<Style x:Key="BaseContentControlStyle" 
       TargetType="ContentControl">
  <Setter Property="Template" Value="{StaticResource BaseContentControlTemplate}" />
</Style>

某些ContentControl,例如Button,可能需要其他状态,例如Pressed。您可以通过创建一种基本样式来扩展其他基本的视觉状态,例如以ButtonBase为目标,并且可以与从ButtonBase派生的任何控件一起使用:

<Style x:Key="BaseButtonStyle" 
       TargetType="ButtonBase" 
       BasedOn="{StaticResource BaseContentControlStyle}">
  <Style.Triggers>
    <Trigger Property="IsPressed" Value="True">
      <Setter Property="Background" Value="{StaticResource HighlightBrush}" />
    </Trigger>
  </Style.Triggers>
</Style>

要应用此基本样式,您必须显式定位控件。您可以使用这种样式来添加更具体的视觉状态或布局,例如ListBoxItem.IsSelctedToggleButton.IsCheckedDataGridColumnHeader

<!-- Buttons -->
<Style TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}" />

<Style TargetType="ToggleButton" BasedOn="{StaticResource BaseButtonStyle}">
  <Style.Triggers>
    <Trigger Property="IsChecked" Value="True">
      <Setter Property="Background" Value="{StaticResource HighlightBrush}" />
    </Trigger>
  </Style.Triggers>
</Style>

<!- ListBox -->
<Style TargetType="ListBoxItem" BasedOn="{StaticResource BaseContentControlStyle}">
  <Style.Triggers>
    <Trigger Property="IsSelected" Value="True">
      <Setter Property="Background" Value="{StaticResource HighlightBrush}" />
    </Trigger>
  </Style.Triggers>
</Style>

<!-- ListView -->
<Style TargetType="ListViewItem" BasedOn="{StaticResource {x:Type ListBoxItem}}" />

<!-- 
  GridView 
  Since GridViewColumnHeader is also a ButtonBase we can extend existing style 
-->
<Style TargetType="GridViewColumnHeader" BasedOn="{StaticResource BaseButtonStyle}" />

<Style x:Key="BaseGridViewStyle" TargetType="ListViewItem">
  <Style.Triggers>
    <Trigger Property="IsSelected" Value="True">
      <Setter Property="Background" Value="{StaticResource HighlightBrush}" />
    </Trigger>
    <Trigger Property="IsMouseOver" Value="True">
      <Setter Property="Background" Value="{StaticResource {x:Static SystemColors.HighlightBrushKey}}" />
    </Trigger>
  </Style.Triggers>
</Style>

<!-- 
  DataGrid
  Since DataGridColumnHeader is also a ButtonBase we can extend existing style 
-->
<Style TargetType="DataGridColumnHeader" 
       BasedOn="{StaticResource BaseButtonStyle}">
  <Setter Property="BorderThickness" Value="1,0" />
  <Setter Property="BorderBrush" Value="{StaticResource BorderBrush}" />
</Style>

其他更复杂的组成控件,例如ComboBoxTreeViewMenuItem,需要分别覆盖控件的模板。由于这些控件由其他控件组成,因此通常也必须覆盖此控件的样式。例如,ComboBoxTextBoxToggleButtonPopup组成。
您可以在Microsoft Docs: Control Styles and Templates上找到它们的样式。

这是将主题添加到应用程序中的非常简单和基本的方法。了解控件的继承树有助于创建可重用的基本样式。重用样式有助于减少定位和自定义每个控件的工作量。
将所有视觉资源(如颜色或图标)定义在一个位置,可以轻松地对其进行修改,而不必分别了解/修改每个控件。

答案 1 :(得分:0)

如果您查看默认样式(https://docs.microsoft.com/en-us/dotnet/framework/wpf/controls/button-styles-and-templates),就会发现每种样式都使用static resources声明颜色。 因此,要完成您的项目,您将不得不覆盖存储颜色的这些static resources

不幸的是,这在WPF中是不可能的(之前已经有人问过:Override a static resource in WPF)。

因此,您唯一的解决方案是为每个控件编写一个单独的Style并重新声明颜色。