【问题标题】:Changing Colors in WPF Style Programmatically -- Application Resource以编程方式更改 WPF 样式中的颜色 -- 应用程序资源
【发布时间】:2016-01-30 01:16:53
【问题描述】:

我已经简化了一些代码。 Style 定义更符合我正在处理的实际程序中的内容,而不是原始样本的所有自动生成的绒毛——对于 Window Resource 样本和我试图移动到 w/应用程序资源示例。

我还在应用程序资源示例中“标记”了基于DependencyObject 的绑定到appColors.appColor。我也玩过一些INotifyPropertyChanged,但还没有让它正常工作。我在AppAppColors 课程中都试过这个。

基于Changing Colors in WPF Style Programmatically,我能够使用转换器和 DependencyProperty 值以编程方式更改文本框的前景色。使用本地 Windows 资源生成的代码如下:

MainWindow.xaml:

<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:Name="LocalWindow" x:Class="ColorLocal.MainWindow"
        xmlns:local="clr-namespace:ColorLocal"
        Title="MainWindow" Height="122.321" Width="269.87">
    <Window.Resources>
        <local:ColorToSolidColorBrushConverter x:Key="ColorToSolidColorBrushConverter" />
        <Style x:Key="LocalTextBoxStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
            <Setter Property="Foreground" Value="{Binding ElementName=LocalWindow, Path=localColor, Converter={StaticResource ColorToSolidColorBrushConverter}}"/>
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" Style="{DynamicResource LocalTextBoxStyle}"/>
        <Button x:Name="btnRed" Content="Red" HorizontalAlignment="Left" Margin="10,47,0,0" VerticalAlignment="Top" Width="75" Click="btnRed_Click"/>
        <Button x:Name="btnGreen" Content="Green" HorizontalAlignment="Left" Margin="90,47,0,0" VerticalAlignment="Top" Width="75" Click="btnGreen_Click"/>
        <Button x:Name="btBlue" Content="Blue" HorizontalAlignment="Left" Margin="170,47,0,0" VerticalAlignment="Top" Width="75" Click="btBlue_Click"/>
        <Button x:Name="btnNewWindow" Content="New Window" HorizontalAlignment="Left" Margin="170,10,0,0" VerticalAlignment="Top" Width="75" Click="btnNewWindow_Click"/>

    </Grid>
</Window>

MainWindow.xaml.cs

namespace ColorLocal
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static readonly DependencyProperty localColorProperty = DependencyProperty.Register("localColor", typeof(Color?), typeof(MainWindow), new PropertyMetadata(Colors.Purple));

        public Color? localColor
        {
            get { return (Color?)GetValue(localColorProperty); }
            set { SetValue(localColorProperty, value); }
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnRed_Click(object sender, RoutedEventArgs e)
        {
            this.localColor = Colors.Red;
        }

        private void btnGreen_Click(object sender, RoutedEventArgs e)
        {
            this.localColor = Colors.Green;
        }

        private void btBlue_Click(object sender, RoutedEventArgs e)
        {
            this.localColor = Colors.Blue;
        }

        private void btnNewWindow_Click(object sender, RoutedEventArgs e)
        {

        }
    }

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

此代码生成一个对话框,其中包含一个 TextBox,其文本最初为紫色,3 个按钮标记为 RedGreen、&Blue,以及另一个标有新窗口的按钮。按下相应的颜色按钮,更改 TextBox 中文本的颜色。新窗口按钮什么都不做。

我现在要将它移动到 应用程序资源 中,我可以将它分配给不同窗口上的所有控件,并在整个程序中进行颜色更改。我按照附加代码段中的详细说明进行了更改。我最初在 App.xaml.cs 代码中使用 DependencyObject 值时遇到问题,但发现了另一篇关于此的帖子。但是,即使在 MainWindow TextBox 上,TextBox 的前景色仍然是黑色(我还没有编写围绕新窗口按钮按下的逻辑)。

任何想法/方向将不胜感激。

我已经更新了代码示例这个提供的代码更符合实际的编码

App.xaml

<Application
             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:Name="LocalApp" x:Class="ColorApp.App"
             xmlns:local="clr-namespace:ColorApp"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <local:ColorToSolidColorBrushConverter x:Key="ColorToSolidColorBrushConverter" />
        <Style x:Key="AppTextBoxStyle" TargetType="{x:Type TextBox}" BasedOn="{x:Null}">
            <Setter Property="Foreground" Value="{Binding appColors.appColor, Converter={StaticResource ColorToSolidColorBrushConverter}, ElementName=LocalApp}"/>
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
        </Style>
    </Application.Resources>
</Application>

App.xaml.cs

namespace ColorApp
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public AppColors appColors = new AppColors();
    }

    public class AppColors : DependencyObject
    {
        public static readonly DependencyProperty appColorProperty = DependencyProperty.Register("appColor",
                                typeof(Color?), typeof(AppColors), new PropertyMetadata(Colors.Purple));

        public Color? appColor
        {
            get { return (Color?)this.GetValue(appColorProperty); }
            set { this.SetValue(appColorProperty, value); }
        }
    }

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

MainWindow.xaml

<Window x:Class="ColorApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="122.321" Width="269.87">
    <Grid>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" Style="{DynamicResource AppTextBoxStyle}"/>
        <Button x:Name="btnRed" Content="Red" HorizontalAlignment="Left" Margin="10,47,0,0" VerticalAlignment="Top" Width="75" Click="btnRed_Click"/>
        <Button x:Name="btnGreen" Content="Green" HorizontalAlignment="Left" Margin="90,47,0,0" VerticalAlignment="Top" Width="75" Click="btnGreen_Click"/>
        <Button x:Name="btBlue" Content="Blue" HorizontalAlignment="Left" Margin="170,47,0,0" VerticalAlignment="Top" Width="75" Click="btBlue_Click"/>
        <Button x:Name="btnNewWindow" Content="New Window" HorizontalAlignment="Left" Margin="170,10,0,0" VerticalAlignment="Top" Width="75" Click="btnNewWindow_Click"/>

    </Grid>
</Window>

MainWindow.xaml.cs

namespace ColorApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnRed_Click(object sender, RoutedEventArgs e)
        {
            ((App)Application.Current).appColors.appColor = Colors.Red;
        }

        private void btnGreen_Click(object sender, RoutedEventArgs e)
        {
            ((App)Application.Current).appColors.appColor = Colors.Green;
        }

        private void btBlue_Click(object sender, RoutedEventArgs e)
        {
            ((App)Application.Current).appColors.appColor = Colors.Blue;
        }

        private void btnNewWindow_Click(object sender, RoutedEventArgs e)
        {

        }
    }
}

【问题讨论】:

  • 这主要是一个代码转储,你能把它归结为一个很小的minimal reproducible example,也许开始一个新项目并取出所有额外的东西?
  • 嗯,这是一个示例可行的项目,旨在展示我在一个更大的项目中所经历的事情。前半部分是使用本地 Windows 资源样式的工作代码,该样式根据原始问题的输入按预期工作。第二组代码是一个示例,演示了我如何尝试将其作为应用程序资源来完成。程序运行,但文本框颜色与第一个代码集相比没有变化。
  • App 本身继承自 Application 不是依赖对象,我想知道这是否导致了问题。在黑暗中射击:尝试在App 上实施INotifyPropertyChanged 并在appColor 上通知。话虽这么说,你的结构中有一些不稳定的东西,我还不能指手画脚。我认为那里有一对多的间接...如果我是对的,您可以将整个 AppColors 类扔掉并通知 App 类。
  • Ok -- 添加 AppColors 是因为另一篇 StackOverflow 文章突出显示 App 类不是基于 DependencyObject 与 MainWindow 不同,这就是为什么我收到“非静态字段需要对象引用”的编译错误、方法或属性”第一篇提到了 cmets。
  • 问题是你在App上绑定到appColor。如果发生变化,则没有通知工具。您可以直接实现 INotifyPropertyChanged 并丢弃您的辅助构造,或者通过仍需要通知工具的代理以某种方式将其插入其中。

标签: c# wpf xaml


【解决方案1】:

您的绑定不正确

在 App.xaml 中,您需要将前台绑定更改为:

<Setter Property="Foreground" Value="{Binding Path=appColors.appColor, Converter={StaticResource ColorToSolidColorBrushConverter}, Source={x:Static Application.Current}}"/>

按照你的风格。

并将 App.xaml.cs 中的 App 类更改为:

public partial class App : Application
{

    public AppColors appColors { get; set; }

    protected override void OnStartup(StartupEventArgs e)
    {
        this.appColors = new AppColors();

        base.OnStartup(e);
    }
}

所以它会被初始化并正确设置。

刚刚试了一下,效果很好。

【讨论】:

  • 谢谢。它正在工作。我在这方面接近了几次,但从未找到正确的组合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2019-04-22
  • 2011-10-07
相关资源
最近更新 更多