Mahapps.metro: Create Binding to the accent and theme elements so they can change at runtime.

Created on 14 Oct 2018  路  2Comments  路  Source: MahApps/MahApps.Metro

Is your feature request related to a problem? Please describe.
I want one of my controls background to have the Accent brush. If I used the static resource way, the control will not change its background color if I changed the application accent at runtime. We need a way to create Binding to the color I need.

Describe the solution you'd like
First step of solution is to create a helper class with properties of the colors and brushes of both the theme and accent, and implement INotifyPropertyChanged interface.... Now we can create this helper class in the App resource and bind our control's property to its properties, and they will change there colors if I changed the theme and accent at runtime.... The helper class code may look like this:

``` C#
using System;
using System.Collections.Generic;
using System.Linq;
using MahApps.Metro;
using System.Windows.Media;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace CM
{
public class ThemeChange : INotifyPropertyChanged
{
#region Theme Change
List properties;
private void ThemeChanged(object sender, OnThemeChangedEventArgs e)
{
if (properties == null) properties = GetType().GetProperties().Select(p => p.Name).ToList();
foreach (var item in properties)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(item));
}
}
#endregion
public ThemeChange()
{
ThemeManager.IsThemeChanged += ThemeChanged;
}
#region Accent Properties
Accent GetAccent()
{
var a = ThemeManager.DetectAppStyle()?.Item2;
if (a == null) a = ThemeManager.GetAccent("Cyan");
return a;
}
T GetItem([CallerMemberName]string key = null) => (T)GetAccent().Resources[key];
public event PropertyChangedEventHandler PropertyChanged;
public Brush AccentColorBrush => GetItem();
public Brush AccentColorBrush2 => GetItem();
public Brush AccentColorBrush3 => GetItem();
public Brush AccentColorBrush4 => GetItem();
public Brush AccentBaseColorBrush => GetItem();
public Brush WindowTitleColorBrush => GetItem();
public Brush IdealForegroundColorBrush => GetItem();
public Brush IdealForegroundDisabledBrush => GetItem();
public Brush AccentSelectedColorBrush => GetItem();
#endregion
#region Theme Properties
AppTheme GetTheme()
{
var a = ThemeManager.DetectAppStyle()?.Item1;
if (a == null) a = ThemeManager.GetAppTheme("BaseLight");
return a;
}
T GetThemeItem([CallerMemberName]string key = null) => (T)GetTheme().Resources[key];
public Brush ControlBackgroundBrush => GetThemeItem();
public Brush WhiteBrush => GetThemeItem();
#endregion
}
}

Second step to make life easier is to create a MarkupExtension To use it directly in our code without the need to create a helper object in the App Resource. The MarkupExtension code may looks like this:

``` C#
using System;
using System.Windows.Data;
using System.Windows.Markup;

namespace CM
{
    public enum ThemeElement
    {
        AccentColorBrush,
        AccentColorBrush2,
        AccentColorBrush3,
        AccentColorBrush4,
        AccentBaseColorBrush,
        WindowTitleColorBrush,
        IdealForegroundColorBrush,
        IdealForegroundDisabledBrush,
        AccentSelectedColorBrush,

        ControlBackgroundBrush,
        WhiteBrush
    }
    public class ThemeBinding : MarkupExtension
    {
        static ThemeChange themeChange = new ThemeChange();
        public ThemeElement Element { get; set; }
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var binding = new Binding(Enum.GetName(typeof(ThemeElement), Element)) { Source = themeChange, Mode = BindingMode.OneWay };
            var expression = binding.ProvideValue(serviceProvider);
            return expression;
        }
    }
}

And we can use it in our code like this:

<Grid Background="{cm:ThemeBinding Element=AccentColorBrush}">
.
.
.
</Grid>

Additional context

Closed Issues

Feature Request

Most helpful comment

If I used the static resource way, the control will not change its background color if I changed the application accent at runtime.

Why are you using StaticResource instead of DynamicResource if you want dynamic changes?

All 2 comments

If I used the static resource way, the control will not change its background color if I changed the application accent at runtime.

Why are you using StaticResource instead of DynamicResource if you want dynamic changes?

You are right in that point.... DynamicResource will solve the problem.....

However, the binding way can give auto complete in xaml editor.... If you are working on that in another way it would be not necessary also.

Best Regards

Was this page helpful?
0 / 5 - 0 ratings