Reputation: 3738
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.
Upvotes: 1
Views: 15412
Reputation: 2580
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
Upvotes: 6
Reputation: 1
ITheme
has a SetPrimaryColor
and SetSecondaryColor
method, maybe it wasn't there before. You can also address properties (like primaryLight
, secondaryMid
, ...) of a theme directly and individually.
private readonly PaletteHelper _paletteHelper = new PaletteHelper();
ITheme theme = _paletteHelper.GetTheme();
theme.SetPrimaryColor(System.Windows.Media.Color.FromRgb(200, 0, 0)); //red
_paletteHelper.SetTheme(theme);
Upvotes: 0
Reputation: 58
Question is quite old but maybe it will help someone else. I think you are missing some entries in your xaml dictionary (related to Accent colors). Minimum should be similar to following
<Application x:Class="MaterialTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
But this is not enough in your case. You are integrating with MahApp.Metro Please follow this link to find more about integration: https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/wiki/MahApps.Metro-integration
Seems like you have your themes hardcoded. It is better to get list of available themes directly from library. Then you can use this like that:
SwatchesProvider swatchesProvider = new SwatchesProvider();
List<string> PrimaryColorsList = swatchesProvider.Swatches.Select(a => a.Name).ToList();
this.primaryPaletteComboBox.Items.AddRange(PrimaryColorsList);
private void primaryPaletteComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
SwatchesProvider swatchesProvider = new SwatchesProvider();
Swatch color= swatchesProvider.Swatches.FirstOrDefault(a => a.Name == this.primaryPaletteComboBox.Text);
paletteHelper.ReplacePrimaryColor(color);
}
Upvotes: 1
Reputation: 3738
This is my work around, it's not the answer.
So at startup, the default palette is set in App.xaml:
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.SWATCHNAME.xaml" />
What I'm doing to change it at runtime is:
Uri uri = new Uri($"pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.{SWATCHNAME}.xaml");
System.Windows.Application.Current.Resources.MergedDictionaries.RemoveAt(4);
System.Windows.Application.Current.Resources.MergedDictionaries.Insert(4, new ResourceDictionary() { Source = uri });
This does what I want in the sense that I can specify a single color swatch, and not have to specify an accent, or set the Hue indices, in the Palette
constructor.
The resource in question is always at index 4, so for now I'm going with it as no keys are defined in App.xaml.
The only other caveat is only some elements are changed at runtime. The app has to be restarted before all of the elements get the new colors, by using the same lines of code in AppStart.cs.
I hope this helps someone else. (note the SWATCHNAME placeholder, and your specific resource index)
If anyone has a better idea, lay it on me.
Upvotes: 2