简体   繁体   中英

WPF Binding color in ResourceDictionary

I'm learning WPF and in my application I want to use accent color that is defined by user. All my styles are defined in Style.xaml which is a ResourceDictionary . What I want to achieve is this:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Namespace"
    x:Class="Namespace.Style"
    x:ClassModifier="public">

    <Color x:Key="AccentColor" 
        A="{Binding Accent.A}"
        R="{Binding Accent.R}"
        G="{Binding Accent.G}"
        B="{Binding Accent.B}" />
    <SolidColorBrush x:Key="AccentBrush" Color="{Binding AccentColor}"/>
</ResourceDictionary>

And in Style.xaml.cs :

namespace Namespace
{
    public partial class Style : ResourceDictionary
    {
        // this color can be changed later
        public Color Accent { get; set; }

        public Style()
        {
            Accent = Color.FromRgb(0x13, 0xaf, 0xf0);

            InitializeComponent();
        }
    }
}

Code above gives error:

'A 'Binding' cannot be set on the 'A' property of type 'Color'. 
 A 'Binding' can only be set on a DependencyProperty of a DependencyObject.'

What are other ways (preferably not too complex, but also flexible) to implement this feature to let user define his own accent color for application's theme?

I would advise against "getting a colour from code behind.

Often you want a brush but sometimes a colour. Here's how I usually define these:

<Color x:Key="PaleBlue">#44A7F7</Color>
<Color x:Key="PaleRed">#F75B71</Color>
<SolidColorBrush x:Key="PaleBlueBrush" Color="{StaticResource PaleBlue}"/>
<SolidColorBrush x:Key="PaleRedBrush" Color="{StaticResource PaleRed}"/>

These go in a resourcedictionary which is merged in app.xaml so they have scope for the entire app.

If I wish to change a theme I define another resource dictionary for ( say ) Dark Theme and another for Blue Theme... and so on.

To change themes I merge the appropriate resource dictionary into application.current.resources and they then replace the original. You need to use DynamicResource to reference these if you want them to change immediately but often a theme change is an unusual thing and "just" totally reloading your window is acceptable.

You can replace one of those in code if you really wanted to.

Application.Current.Resources["PaleRedBrush"] = // some new solidcolorbrush.

A lot of things in a resourcedictionary are frozen ( there's a Freeze() method ) and you can't change them. I never tried to implement exactly what you're doing there but I think it might be problematic.

You could alternatively use a bridging static dependency object or class which implements inotifypropertychanged. One candidate would involve a observabledictionary as property in a static. That'd allow you to bind to brush by string as name. http://drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/ Not tried that neither.

You don't need anything in the Styles.xaml.cs. Create a Styles.xaml ResourceDictionary:

<ResourceDictionary>
    <SolidColorBrush x:Key="AccentColor" Color="#FFFFFF" />
</<ResourceDictionary>

To use this color in the other xaml files, you will have to declare it inside the merged dictionary tag along with it's path:

<Window>
<Window.Resources>
<ResourceDictionary x:Uid="ResourceDictionary_1">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Styles.xaml"/>
    </ResourceDictionary.MergedDictionaries>
</Window.Resources>
<TextBlock Background="{StaticResource AccentColor}"/>
</Window>

You can use it the way I used to apply the TextBlock background. You will have to provide the path of your Styles.xaml in the Source tag of ResourceDictionary.

I use this . The demo comes with a style switch implementation. You can take a look at the example to see how it works, it's all open source.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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