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

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

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

2 ответа

Решение

Вот фрагмент кода, который я использовал в своем приложении, которое поддерживало тематику. В этом примере у меня есть две темы (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}" />

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

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

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

Другие вопросы по тегам