简体   繁体   English

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

[英]Changing Colors in WPF Style Programmatically

First off, I have somewhat accomplished what I am about to ask creating different styles with different Foreground/Background colors (for example) and then in the code doing either 首先,我已经完成了我要问的用不同的前景/背景色创建不同样式的要求,然后在代码中执行

Control.Style = new_style

or 要么

this.Resources["MyStyle"] = new_style

I was happy with that until I hit an issue w/ the ComboBox control where I was wanting to programmatically change the color of the arrow on the dropwdown button. 我对此感到满意,直到遇到带有ComboBox控件的问题,我想以编程方式更改下拉按钮上箭头的颜色。 This appears to get into Control Template changes to set that so I decided to approach my colors changes from another route -- setting the color values within the Style or Control Template using Binding. 这似乎是要进入“控制模板更改”设置的,所以我决定从另一条路线处理我的颜色更改-使用“绑定”在“样式”或“控制模板”中设置颜色值。 So I created a test program starting simple and planning to workup to the Control Template changes but I have yet to get "simple" working. 因此,我创建了一个测试程序,从简单开始,并计划对控制模板进行更改,但是我还没有开始“简单”的工作。 My test program consists of a Textbox and a Button and I am trying to change the foreground color within the text box. 我的测试程序由一个文本框和一个按钮组成,我试图在文本框中更改前景色。 The basic XML code is (less some lines): 基本的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>

Then in the code I have: 然后在代码中,我有:

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

The idea being that if I want to change the foreground color, pvColor just needs to change within the program. 这样的想法是,如果我想更改前景色,则只需在程序中更改pvColor。

For whatever reason this is not working. 无论出于什么原因,这都不起作用。 I am hoping I am just overlooking something simple in the code that I have yet to see/find. 我希望我只是忽略了我尚未看到/发现的简单代码。 If I define fgColor in the Window.Resources as below, that works -- I get Pink text: 如果我在如下的Window.Resources中定义fgColor,则可以正常工作-我得到粉红色的文本:

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

Any ideas or direction would be greatly appreciate. 任何想法或方向将不胜感激。

Thanks 谢谢

Update 1: I updated the code snippet to reflect the use of Color rather than Brush. 更新1:我更新了代码片段以反映使用颜色而不是画笔的用法。 I have also tried Frank J's INotifyPropertyChanged option and also the Dependence Property option but neither have worked yet. 我也尝试了Frank J的INotifyPropertyChanged选项和Dependency Property选项,但是都没有用。 The Dependence Property complained that Color was not nullable. Dependency属性抱怨Color不能为空。

-- Update -更新

I looked at your code again. 我再次查看了您的代码。

The problem that you have is that the color of the SolidColorBrush is changing but not the ressource itself and therefore the change doesn't get propagated. 您遇到的问题是,SolidColorBrush的颜色正在更改,但资源本身未更改,因此更改不会传播。

2 possible solutions: 2种可能的解决方案:

1) You can change the requirement from having a property set the the brushes color to make the change to changing the ressource itself which will propagate the DynamicResource change (Press the button to see the switch): 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) Alternatively you bind the styles Foreground directly to the variable via the converter instead of going through the Ressource (again press the button to see the change): 2)另外,您也可以通过转换器将前景样式直接绑定到变量,而不用通过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;
    }
}

For both solutions change the namespace accordingly in the code. 对于这两种解决方案,请在代码中相应地更改名称空间。

SolidColorBrush.Color expects a Color not another Brush . 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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM