Можно ли использовать темы WPF для включения нескольких скинов для приложения, которое можно изменить во время выполнения?

WPF позволяет библиотеке управления предоставлять различные ресурсные словари для разных системных тем, что позволяет приложению соответствовать выбранной визуальной теме операционной системы (Aero, Luna и т.д.).

Мне интересно, могу ли я включить несколько тематических ресурсных словарей с моим приложением и использовать некоторую существующую поддержку темы в рамках. Это должно работать для моих собственных имен тем и в идеале позволяет пользователю изменять тему и, следовательно, внешний вид приложения во время выполнения. Даже если это только настройка конфигурации, это все равно может быть интересно.

Ответ 1

Вот фрагмент кода, который я использовал в своем приложении, поддерживающем их. В этом примере у меня есть две темы (Default и Classic XP). Ресурсы темы хранятся в DefaultTheme.xaml и ClassicTheme.xaml соответственно.

Это код по умолчанию в моем 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>

Затем в коде App.xaml у меня есть следующий способ, позволяющий изменить тему. В основном, то, что вы делаете, это очистить Словари ресурсов, а затем перезагрузить словарь новой темой.

    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);
    }

То, что вам также нужно учитывать при таком подходе, состоит в том, что для любых стилей, которые используют тему, потребуется динамический ресурс. Например:

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

Ответ 2

Я не знаю, как это сделать в рамках, но вы можете сделать это, если будете создавать каждый элемент управления, который может изменить себя.

Теория состоит в том, чтобы сделать стиль a DynamicResource, а затем загрузить ResourcesDictionary на основе конфигурации пользователей для другого стиля.

Здесь - статья, в которой есть пример.