以编程方式更改WPF样式中的颜色

本文关键字:颜色 样式 WPF 编程 方式更 | 更新日期: 2023-09-27 18:14:06

首先,我已经在一定程度上完成了我要问的用不同的前景/背景颜色创建不同的样式(例如),然后在代码中执行

Control.Style = new_style

this.Resources["MyStyle"] = new_style

我对此很满意,直到我在ComboBox控件中遇到了一个问题,我想通过编程改变下拉按钮上箭头的颜色。这似乎进入了控制模板更改的设置,所以我决定从另一种途径来处理我的颜色更改——使用绑定在样式或控制模板中设置颜色值。所以我创建了一个测试程序,开始简单,并计划对控制模板的变化进行处理,但我还没有得到"简单"的工作。我的测试程序包括一个文本框和一个按钮,我试图改变文本框内的前景色。基本的XML代码是(少了一些行):

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" x:Class="ColorTest4.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <SolidColorBrush x:Key="FGColor" Color="{Binding fgColor}"/>
    </Window.Resources>
    <Grid>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" Style="{DynamicResource TextBoxStyle1}">
            <TextBox.Resources>
                <LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
                    <GradientStop Color="#ABADB3" Offset="0.05"/>
                    <GradientStop Color="#E2E3EA" Offset="0.07"/>
                    <GradientStop Color="#E3E9EF" Offset="1"/>
                </LinearGradientBrush>
                <Style x:Key="TextBoxStyle1" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
                    <Setter Property="Foreground" Value="{DynamicResource FGColor}"/>
                    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
                    <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
                    <!--<Some Setter Properties & Style.Triggers removed for conciseness >-->
                </Style>
            </TextBox.Resources>
        </TextBox>
        <Button Content="Button" HorizontalAlignment="Left" Margin="433,10,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

然后在代码中我有:

private Color pvColor = Colors.Green;
private Color fgColor
{
    get { MessageBox.Show("fgColor");  return pvColor; }
}

的想法是,如果我想改变前景的颜色,pvColor只需要改变程序内。

无论出于什么原因,这都不起作用。我希望我只是忽略了一些简单的代码,我还没有看到/找到。如果我在窗口中定义fgColor。资源如下,这是有效的——我得到粉红色的文本:

<Window.Resources>
    <SolidColorBrush x:Key="FGColor" Color="Pink"/>
</Window.Resources>

如有任何建议或指导,不胜感激。

感谢

更新1:我更新了代码片段以反映颜色而不是画笔的使用。我也尝试过Frank J的INotifyPropertyChanged选项和依赖属性选项,但都没有起作用。依赖性属性抱怨Color不可为空

以编程方式更改WPF样式中的颜色

—Update

我又看了你的代码。

你的问题是,SolidColorBrush的颜色正在改变,但资源本身没有改变,因此改变没有得到传播。

2种可能的解决方案:

1)你可以改变要求,从有一个属性设置笔刷的颜色来改变改变,改变资源本身,这将传播动态资源的变化(按下按钮看到开关):

<Window x:Class="SOTextBoxForeground.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SOTextBoxForeground"
    Title="MainWindow" Height="350" Width="525" Name="MyWindow">
<Window.Resources>
      <SolidColorBrush x:Key="FGColor" Color="Green"/>
   </Window.Resources>
   <Grid>
      <Grid.Resources>
         <Style x:Key="TextBoxStyle1" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
            <Setter Property="Foreground" Value="{DynamicResource FGColor}"/>
         </Style>
      </Grid.Resources>
      <TextBox HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" Style="{StaticResource TextBoxStyle1}" />
      <Button Content="Button" HorizontalAlignment="Left" Margin="433,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
   </Grid>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.Resources["FGColor"] = new SolidColorBrush(Colors.Blue);
    }
}

2)或者你可以通过转换器直接将样式前景绑定到变量,而不是通过资源(再次按下按钮以查看更改):

<Window x:Class="SOTextBoxForeground.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SOTextBoxForeground"
        Title="MainWindow" Height="350" Width="525" Name="MyWindow">
      <Window.Resources>
      <local:ColorToSolidColorBrushConverter x:Key="ColorToSolidColorBrushConverter" />
   </Window.Resources>
   <Grid>
      <Grid.Resources>
         <Style x:Key="TextBoxStyle1" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
            <Setter Property="Foreground" Value="{Binding ElementName=MyWindow, Path=pvColor, Converter={StaticResource ColorToSolidColorBrushConverter}}"/>
         </Style>
      </Grid.Resources>
      <TextBox HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" Style="{StaticResource TextBoxStyle1}" />
      <Button Content="Button" HorizontalAlignment="Left" Margin="433,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
   </Grid>
</Window>
public class ColorToSolidColorBrushConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
     Color? desiredColor = value as Color?;
     if (desiredColor != null)
     {
        return new SolidColorBrush(desiredColor.Value);
     }
     //Return here your default
     return DependencyProperty.UnsetValue;
  }
  public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
     return DependencyProperty.UnsetValue;
  }
}
public partial class MainWindow : Window
{
    public static readonly DependencyProperty pvColorProperty = DependencyProperty.Register("pvColor",
    typeof(Color?), typeof(MainWindow),
    new PropertyMetadata(Colors.Red));
    public Color? pvColor
    {
        get { return (Color?)GetValue(pvColorProperty); }
        set { SetValue(pvColorProperty, value); }
    }
    public MainWindow()
    {
        InitializeComponent();
    }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.pvColor = Colors.Blue;
    }
}
public class ColorToSolidColorBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Color? desiredColor = value as Color?;
        if (desiredColor != null)
        {
            return new SolidColorBrush(desiredColor.Value);
        }
        //Return here your default
        return DependencyProperty.UnsetValue;
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return DependencyProperty.UnsetValue;
    }
}

对于这两种解决方案,在代码中相应地更改命名空间

SolidColorBrush.Color期望一个Color而不是另一个Brush

private Color pvColor = Colors.Green;
public Color fgColor
{
    get { return pvColor; }
    set
    {
        pvColor = value;
        this.OnPropertyChanged("fgColor"); // Make sure you have INotifyPropertyChanged implemented
    }
}