Upendhar Singirikonda
Upendhar Singirikonda

Reputation: 179

Change Theme Dynamically Telerik WPF

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

Answers (3)

Damien
Damien

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

Vanghern
Vanghern

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

kmatyaszek
kmatyaszek

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
  • 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

Upvotes: 1

Related Questions