Change Theme Dynamically Telerik WPF
Asked Answered
G

3

6

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.

Godrich answered 25/8, 2018 at 5:48 Comment(0)
T
1

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
  • Theme assemblies, in my case it's: 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/stylemanager/common-styling-apperance-setting-theme-wpf

https://docs.telerik.com/devtools/wpf/styling-and-appearance/how-to/styling-apperance-themes-runtime

Tchao answered 25/8, 2018 at 6:53 Comment(7)
Thank you. But that way, I have to re-run my application right? Without closing and re-open it, I think it will not work. So, I am setting theme at control level and changing it. But doing so, need to take care XAML very well, which looks bit tedious for which I am looking for alternatives...Godrich
@UpendharSingirikonda please check my answer again.Tchao
thank you again. But, for some reasons, I can't have app.xaml as I am embedding my solution to another application. So, I will try with this.resources.mergedict... Except overhead of adding theme to every control in XAML, is my initial approach also fine in terms of stability and performance when compared to this approach? Which is more stable, reliable and performant way?Godrich
@UpendharSingirikonda I think that solution with application resources is the correct way to do that. Your code base will be more clear, the code responsible for application theme will be in one place.Tchao
Ok, thank you. But, when I refer NoXAML Dlls sometimes, my view is not rendering and I am getting some problems like few controls not changing theme dynamically, etc... I will checkGodrich
To change themes at runtime, use the NoXaml dlls and the Implicit Styles theming mechanisms. Check Setting a Theme article. This means that you will need to avoid using StyleManager and use only Implicit Style. Check also Switching Themes at Runtime and Missing Controls in the UI articles.Sophy
Having the same issue, referencing Theme lib breaks my UIKally
P
1

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.

Pentheus answered 7/9, 2018 at 8:57 Comment(0)
K
0

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());
    }
Kally answered 1/9, 2022 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.