Темы

Последнее обновление: 18.10.2016

Стили позволяют задать стилевые особенности для определенного элемента или элементов одного типа. Но иногда возникает необходимость применить ко всем элементам какое-то общее стилевое единообразие. И в этом случае мы можем объединять стили элементов в темы. Например, все элементы могут выполнены в светлом стиле, или, наоборот, к ним может применяться так называемая "ночная тема". Более того может возникнуть необходимость не просто определить общую тему для всех элементов, но и иметь возможность динамически выбирать понравившуюся тему из списка тем. И в данной статье рассмотрим, как это сделать.

Пусть у нас есть окно приложения с некоторым набором элементов:

<Window x:Class="ThemesApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ThemesApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="300" Style="{DynamicResource WindowStyle}">
    <StackPanel>
        <ComboBox x:Name="styleBox" />
        <Button Content="Hello WPF" Style="{DynamicResource ButtonStyle}" />
        <TextBlock Text="Windows Presentation Foundation" Style="{DynamicResource TextBlockStyle}" />
    </StackPanel>
</Window>

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

К элементам окна уже применяются некоторые стили. Причем следует отметить, что стили указывают на динамические (не статические) ресурсы. Однако сами эти ресурсы еще не заданы. Поэтому зададим их.

Для этого добавим в проект новый файл словаря ресурсов, который назовем light.xaml, и определим в нем некоторый набор ресурсов:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:ThemesApp">
    <Style x:Key="TextBlockStyle" TargetType="TextBlock">
        <Setter Property="Background" Value="White" />
        <Setter Property="Foreground" Value="Gray" />
    </Style>
    <Style x:Key="WindowStyle" TargetType="Window">
        <Setter Property="Background" Value="White" />
    </Style>
    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="White" />
        <Setter Property="Foreground" Value="Gray" />
        <Setter Property="BorderBrush" Value="Gray" />
    </Style>
</ResourceDictionary>

Здесь указаны все те стили, которые применяются элементами окна.

Но теперь также добавим еще один словарь ресурсов, который назовем dark.xaml и в котором определим следующий набор ресурсов:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:ThemesApp">
    <Style x:Key="TextBlockStyle" TargetType="TextBlock">
        <Setter Property="Background" Value="Gray" />
        <Setter Property="Foreground" Value="White" />
    </Style>
    <Style x:Key="WindowStyle" TargetType="Window">
        <Setter Property="Background" Value="Gray" />
    </Style>
    <Style x:Key="ButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="Gray" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="BorderBrush" Value="White" />
    </Style>
</ResourceDictionary>

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

Темы в WPF

Теперь применим эти стили. Для этого изменим файл MainWindow.xaml.cs следующим образом:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace ThemesApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            List<string> styles = new List<string> { "light", "dark" };
            styleBox.SelectionChanged += ThemeChange;
            styleBox.ItemsSource = styles;
            styleBox.SelectedItem = "dark";
        }

        private void ThemeChange(object sender, SelectionChangedEventArgs e)
        {
            string style = styleBox.SelectedItem as string;
			// определяем путь к файлу ресурсов
            var uri = new Uri(style + ".xaml", UriKind.Relative);
			// загружаем словарь ресурсов
            ResourceDictionary resourceDict = Application.LoadComponent(uri) as ResourceDictionary;
			// очищаем коллекцию ресурсов приложения
            Application.Current.Resources.Clear();
			// добавляем загруженный словарь ресурсов
            Application.Current.Resources.MergedDictionaries.Add(resourceDict);
        }
    }
}

К элементу ComboBox цепляется обработчик ThemeChange, который срабатывает при выборе элемента в списке.

В методе ThemeChange получаем выделенный элемент, который представляет название темы. По нему загружаем локальный словарь ресурсов и добавляем этот словарь в коллекцию ресурсов приложения.

В итоге при выборе элемента в списке будет меняться применяемая к приложению тема:

Смена темы в WPF
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850