以编程方式更改 WPF 样式中的颜色
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32725764/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Changing Colors in WPF Style Programmatically
提问by Mark Parr
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. 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):
我对此很满意,直到我遇到了 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>
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. I have also tried Frank J's INotifyPropertyChanged option and also the Dependence Property option but neither have worked yet. The Dependence Property complained that Color was not nullable.
更新 1:我更新了代码片段以反映 Color 而不是 Brush 的使用。我也尝试过 Frank J 的 INotifyPropertyChanged 选项和 Dependence Property 选项,但都没有奏效。依赖属性抱怨 Color 不可为空。
回答by Frank J
-- 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)您可以将要求从设置画笔颜色的属性更改为更改资源本身,这将传播动态资源更改(按按钮查看开关):
<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) 或者,您可以通过转换器将样式 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;
}
}
For both solutions change the namespace accordingly in the code.
对于这两种解决方案,在代码中相应地更改命名空间。
回答by Laith
SolidColorBrush.Colorexpects a Colornot 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
}
}

