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

时间:2015-09-22 19:58:51

标签: c# wpf

首先,我有点完成了我要求创建具有不同前景/背景颜色的不同样式(例如)然后在代码中执行

Control.Style = new_style

this.Resources["MyStyle"] = new_style

我很满意,直到我遇到一个问题与ComboBox控件,我想要以编程方式更改下拉按钮上的箭头颜色。这似乎进入控制模板更改以设置,所以我决定从另一条路线接近我的颜色更改 - 使用Binding在样式或控制模板中设置颜色值。所以我创建了一个简单的测试程序,并计划对控制模板进行更改,但我还没有“简单”工作。我的测试程序包含一个文本框和一个按钮,我试图改变文本框中的前景色。基本的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只需要在程序中改变。

无论出于何种原因,这都行不通。我希望我只是在代码中忽略了一些我尚未看到/找到的东西。如果我在Window.Resources中定义fgColor如下,那就行了 - 我得到粉红色的文字:

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

任何想法或方向都会非常感激。

由于

更新1:我更新了代码段以反映使用Color而不是Brush。我也尝试过Frank J的INotifyPropertyChanged选项以及Dependence Property选项,但两者都没有。 Dependence Property抱怨Color不可为空。

2 个答案:

答案 0 :(得分:1)

- 更新

我再次看了你的代码。

你遇到的问题是SolidColorBrush的颜色正在改变,而不是资源本身,因此改变不会传播。

2种可能的解决方案:

1)您可以通过将属性设置为画笔颜色来更改要求,以更改为更改资源本身,这将传播DynamicResource更改(按按钮查看切换):

<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)或者你可以通过转换器直接将Foreground样式绑定到变量,而不是通过Ressource(再次按下按钮查看更改):

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

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

答案 1 :(得分:-1)

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