Can WPF themes be used to include multiple skins for an application that can be changed at runtime?

只愿长相守 提交于 2019-11-29 12:50:38

问题


WPF allows a control library to provide different resource dictionaries for different system themes, essentially allowing an application to match the operating system's selected visual theme (Aero, Luna, etc).

I'm wondering if I can include multiple theme resource dictionaries with my application and utilise some existing theme support within the framework. This should work for my own theme names, and ideally allow the user to change the theme and therefore the skinned appearance of the application at runtime. Even if this were only a config setting, it could still be interesting.


回答1:


Here is a snippet of code that I used in my application that supported theming. In this example, I have two themes (Default and Classic XP). The theme resources are stored in the DefaultTheme.xaml and ClassicTheme.xaml respectively.

This is the default code in my App.xaml

<Application ...>
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="ArtworkResources.xaml" />
                <ResourceDictionary Source="DefaultTheme.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <Style x:Key="SwooshButton" TargetType="ButtonBase">
                <!-- style setters -->
            </Style>

            <!-- more global styles -->
        </ResourceDictionary>
    </Application.Resources>
</Application>

Then in the code behind of the App.xaml I have the following method to allow for changing the theme. Basically, what you do is clear the Resource Dictionaries and then reload the dictionary with the new theme.

    private Themes _currentTheme = Themes.Default;
    public Themes CurrentTheme
    {
        get { return _currentTheme; }
        set { _currentTheme = value; }
    }

    public void ChangeTheme(Themes theme)
    {
        if (theme != _currentTheme)
        {
            _currentTheme = theme;
            switch (theme)
            {
                default:
                case Themes.Default:
                    this.Resources.MergedDictionaries.Clear();
                    AddResourceDictionary("ArtworkResources.xaml");
                    AddResourceDictionary("DefaultTheme.xaml");
                    break;
                case Themes.Classic:
                    this.Resources.MergedDictionaries.Clear();
                    AddResourceDictionary("ArtworkResources.xaml");
                    AddResourceDictionary("ClassicTheme.xaml");
                    break;
            }
        }
    }

    void AddResourceDictionary(string source)
    {
        ResourceDictionary resourceDictionary = Application.LoadComponent(new Uri(source, UriKind.Relative)) as ResourceDictionary;
        this.Resources.MergedDictionaries.Add(resourceDictionary);
    }

What you'll also need to keep in mind with this approach is that any styles that utilize a theme will need to have a dynamic resource. For example:

<Window Background="{DynamicResource AppBackgroundColor}" />



回答2:


I don't know of a way of doing this in the framework, but you can do it if you style every control that can change yourself.

The theory is to make the style a DynamicResource and then load the ResourcesDictionary based on the users configuration for the different style.

Here is an article that has an example.



来源:https://stackoverflow.com/questions/844388/can-wpf-themes-be-used-to-include-multiple-skins-for-an-application-that-can-be

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!