How to change WPF Material Design Palette at runtime?

rfmodulator picture rfmodulator · Jan 27, 2019 · Viewed 8.1k times · Source

I've recently "upgraded" a solution to a VS2017 and .NET Framework 4.6.1.

I've also updated all of the NuGet packages to their latest versions.

This question likely concerns one or more of the following packages (previous versions are in parenthesizes):

MahApps.Metro by Jan Karger et al. 1.6.5 (1.3.0-ALPHA016)

MaterialDesignColors by James Willock 1.1.3 (1.1.2)

MaterialDesignThemes by James Willock 2.5.0.1205 (1.1.0.234)

MaterialDesignThemes.MahApps by James Willock 0.0.12 (0.0.3)

WPF related packages also being referenced include:

Extended.Wpf.Toolkit by Xceed 3.4.0 (2.6.0)

ControlzEx by Jan Karger et al. 3.0.2.4 (none, new dependency of MahApps.Metro)

Prior to the updates, the following would change the UI color palette at runtime:

private void primaryPaletteComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
   paletteHelper.ReplacePrimaryColor(this.primaryPaletteComboBox.Text);
}

/* Where: */

var paletteHelper = new MaterialDesignThemes.Wpf.PaletteHelper();

this.primaryPaletteComboBox.Items.AddRange(new object[] {
    "Amber",
    "Blue",
    "BlueGrey",
    "Brown",
    "Cyan",
    "DeepOrange",
    "DeepPurple",
    "Green",
    "Grey",
    "Indigo",
    "LightBlue",
    "LightGreen",
    "Lime",
    "Orange",
    "Pink",
    "Purple",
    "Red",
    "Teal",
    "Yellow"});

...Super simple, super easy.

After the updates, ReplacePrimaryColor throws the following exception:

System.InvalidOperationException: 'Unable to safely determine a single resource definition for SecondaryAccentBrush.'

Downgrading these packages to their previous versions cause other problems.

How can I change the color palette at runtime in the most recent version of these packages?

I would like to do this by simply using the color palette name that the user selects from a ComboBox.

Obviously SecondaryAccentBrush is a problem.

Does anyone know what changed in the last few years?

This should be easy, but Google doesn't give me anything useful. Maybe I'm not asking the right question.

PaletteHelper now provides a ReplacePalette(Palette palette) method that looks promising, perhaps there is a way to instantiate a Palette object by using the name of a predefined resource?

I would rather go to the dentist and proctologist at the same time, than to screw around with XAML resource definitions.

Answer

Tino Mclaren picture Tino Mclaren · Feb 18, 2020

You can achieve this using MDIX PaletteHelper.

For Dark/Light

Drop a ToggleButton on your Ui & bind its isChecked bool to the isDark bool used below (Binding or Code behind, however you are wiring your ui up)

    private readonly PaletteHelper _paletteHelper = new PaletteHelper();
    private void ToggleBaseColour(bool isDark)
    {
        ITheme theme = _paletteHelper.GetTheme();
        IBaseTheme baseTheme = isDark ? new MaterialDesignDarkTheme() : (IBaseTheme)new MaterialDesignLightTheme();
        theme.SetBaseTheme(baseTheme);
        _paletteHelper.SetTheme(theme);
    }

For Primary & Accent colours

the MDIX GitHub demo apps PaletteSelector VM has well written & easy to read code here