Reputation: 179
I need to allow user to change themes dynamically in an application created using telerik WPF controls.
I am setting binding to each and every telerik control in my XAML as follows:
XAML:
telerik:StyleManager.Theme="{Binding SelectedSMTheme, Mode=TwoWay}"
ViewModel:
private Theme selectedSMTheme;
public Theme SelectedSMTheme
{
get
{
return selectedSMTheme;
}
set
{
selectedSMTheme = value;
RaisePropertyChange("SelectedSMTheme");
}
}
And changing this SelectedSMTheme
whenever user select a theme.
Changing Theme:
SelectedSMTheme = new Expression_DarkTheme();
Is there any other way to change themes for telerik controls while running application. Because, here I need to specify telerik:StyleManager.Theme
to each n every control throughout the application.
Upvotes: 6
Views: 2049
Reputation: 1552
Same but better, dynamically loads from available theme dlls and applies to whatever used libraries (try {} catch)
void LoadThemeNames()
{
var directory = AppDomain.CurrentDomain.BaseDirectory;
var files = Directory.GetFiles(directory, "Telerik.Windows.Themes.*.dll");
foreach (var item in files)
{
var name = item.Split('.')[3];
ThemeCombo.Items.Add(new RadComboBoxItem() { Content = name.Replace("_", " "), Name = name });
}
}
public void ChangeTheme(string selectedTheme)
{
Application.Current.Resources.MergedDictionaries.Clear();
string[] lst = new string[] {
"System.Windows.xaml",
"Telerik.Windows.Controls.xaml",
"Telerik.Windows.Controls.Input.xaml",
"Telerik.Windows.Controls.Navigation.xaml",
"Telerik.Windows.Controls.Data.xaml",
"Telerik.Windows.Controls.DataVisualization.xaml",
"Telerik.Windows.Controls.Docking.xaml",
"Telerik.Windows.Controls.GridView.xaml",
"Telerik.Windows.Controls.Pivot.xaml",
"Telerik.Windows.Controls.PivotFieldList.xaml",
"Telerik.Windows.Controls.VirtualGrid.xaml"};
foreach (var item in lst)
{
var uri = new Uri("/Telerik.Windows.Themes." + selectedTheme + ";component/Themes/" + item, UriKind.RelativeOrAbsolute);
if (uri != null)
{
try
{
var rsc = new ResourceDictionary { Source = uri };
Application.Current.Resources.MergedDictionaries.Add(rsc);
}
catch (Exception e) { }
}
}
}
private void RadComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ChangeTheme(((RadComboBoxItem)ThemeCombo.SelectedItem).Name.ToString());
}
Upvotes: 0
Reputation: 202
I'm using similar solution as this provided by kmatyaszek, except for, I'm doing it in ComboBox:
private void StyleCombo_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedTheme = StyleCombo.SelectedItem as ThemeNames;
Application.Current.Resources.MergedDictionaries.Clear();
// XAML
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/System.Windows.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.Input.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.Navigation.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.Data.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.DataVisualization.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.Docking.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.GridView.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.Pivot.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.PivotFieldList.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
{
Source = new Uri("/Telerik.Windows.Themes." + selectedTheme.Value + ";component/Themes/Telerik.Windows.Controls.VirtualGrid.xaml", UriKind.RelativeOrAbsolute)
});
}
You've said in comments section, that some controlls are not changing dynamically - it's known problem for NoXaml libraries. What I can recommend to you, is setting parameters manually to those controlls. In my case it looks like this:
// Main Grid
if (selectedTheme.Name == "Visual Studio 2013 Dark")
{
VisualStudio2013Palette.LoadPreset(VisualStudio2013Palette.ColorVariation.Dark);
App.StronaGlowna.MainGrid.Background = (SolidColorBrush)new BrushConverter().ConvertFrom("#FF1E1E1E");
}
if (selectedTheme.Name == "Visual Studio 2013 Blue")
{
VisualStudio2013Palette.LoadPreset(VisualStudio2013Palette.ColorVariation.Blue);
}
if (selectedTheme.Name == "Visual Studio 2013")
{
VisualStudio2013Palette.LoadPreset(VisualStudio2013Palette.ColorVariation.Light);
App.StronaGlowna.MainGrid.Background = Brushes.White;
}
if (selectedTheme.Name == "Dark")
{
VisualStudio2013Palette.LoadPreset(VisualStudio2013Palette.ColorVariation.Dark);
App.StronaGlowna.MainGrid.Background = (SolidColorBrush)new BrushConverter().ConvertFrom("#FF3D3D3D");
}
if (selectedTheme.Name == "Green")
{
GreenPalette.LoadPreset(GreenPalette.ColorVariation.Dark);
App.StronaGlowna.MainGrid.Background = (SolidColorBrush)new BrushConverter().ConvertFrom("#FF1D1E21");
}
if (selectedTheme.Name == "Green Light")
{
GreenPalette.LoadPreset(GreenPalette.ColorVariation.Light);
App.StronaGlowna.MainGrid.Background = (SolidColorBrush)new BrushConverter().ConvertFrom("#FFE0E0E0");
}
if (selectedTheme.Name == "Vista" ||
selectedTheme.Name == "Visual Studio 2013 Blue" || selectedTheme.Name == "Office Black" ||
selectedTheme.Name == "Office Blue" ||
selectedTheme.Name == "Office Silver" || selectedTheme.Name == "Summer" ||
selectedTheme.Name == "Transparent" || selectedTheme.Name == "Windows 7")
{
App.StronaGlowna.MainGrid.Background = Brushes.White;
}
This solution was provided to me by Telerik support in 1 support ticket. You can find most of hex colors of controlls in documentation, for instance this one is for Office2013 theme. Also, bear in mind, that some WPF controlls are unaffected by styling (i think one of examples is TextBox), so if you are using vanilla WPF controlls, they might remain unchanged and require you to hardcode new colors.
Upvotes: 1
Reputation: 19296
You can use StyleManager.ApplicationTheme
to set initial theme. Setting this property affects all controls in your application.
Your App.xaml.cs constructor should look like:
public partial class App : Application
{
public App()
{
StyleManager.ApplicationTheme = new Expression_DarkTheme();
this.InitializeComponent();
}
}
To switch theme at runtime you should clear application resources and add new ones.
private void btnChangeTheme_Click(object sender, RoutedEventArgs e)
{
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = new Uri("/Telerik.Windows.Themes.Green;component/Themes/System.Windows.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = new Uri("/Telerik.Windows.Themes.Green;component/Themes/Telerik.Windows.Controls.xaml", UriKind.RelativeOrAbsolute)
});
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = new Uri("/Telerik.Windows.Themes.Green;component/Themes/Telerik.Windows.Controls.Input.xaml", UriKind.RelativeOrAbsolute)
});
}
You must remember to add required assemblies from the Binaries.NoXaml folder located in the installation folder (in my case it's: C:\Program Files (x86)\Progress\Telerik UI for WPF R2 2018\Binaries.NoXaml
):
Telerik.Windows.Controls.dll
Telerik.Windows.Controls.Input.dll
Telerik.Windows.Themes.Expression_Dark.dll
and Telerik.Windows.Themes.Green.dll
Please read the following article for further information:
https://docs.telerik.com/devtools/wpf/styling-and-appearance/how-to/styling-apperance-themes-runtime
Upvotes: 1