Гид по технологиям

Темы в Windows Forms: переключение светлой, природной и тёмной темы

8 min read Разработка Обновлено 02 Jan 2026
Темы в Windows Forms: светлая, природная, тёмная
Темы в Windows Forms: светлая, природная, тёмная

Код на компьютере рядом с растениями

Современные приложения часто дают пользователю возможность смены темы интерфейса. Один пользователь может предпочесть светлую тему, другой — тёмную, а третий — тему с природной палитрой. В Windows Forms это реализуется через элементы управления: кнопки для выбора темы и код, который применяет цвета к элементам формы.

В этой статье приведён практический пример, где приложение содержит три темы: Light (светлая), Nature (природная) и Dark (тёмная). Вы научитесь:

  • настроить проект и добавить кнопки и метки;
  • создать кнопку «Themes» и список кнопок для каждой темы;
  • хранить цвета в словарях и применять их через функции;
  • тестировать и расширять систему тем;
  • варианты улучшений для продакшн-решений.

Основная идея

Отделяйте палитру (набор цветов) от логики применения этих цветов. Храните палитру в структуре данных (словарь), а код, который изменяет свойства BackColor/ForeColor — в отдельных функциях. Это упрощает поддержку, тестирование и добавление новых тем.

Важно: стандартные контроли WinForms реагируют на изменение BackColor/ForeColor, но кастомные контролы или сторонние библиотеки могут требовать отдельных обработчиков.

Как создать проект Windows Forms

  1. Создайте новый проект Windows Forms в Visual Studio.

  2. Добавьте на форму базовые элементы управления: кнопки и метки.

  3. Создайте новое приложение Windows Forms в Visual Studio.

  4. В тулбоксе найдите элемент Button. Поиск кнопки в тулбоксе Visual Studio

  5. Перетащите элемент Button на форму. Добавьте в сумме три кнопки. Кнопки на форме WinForms

  6. Добавьте Label и разместите её под кнопками. Метка на форме WinForms

  7. Настройте свойства кнопок и метки через окно Properties. Измените их следующим образом:

ЭлементСвойствоНовое значение
button1Size580, 200
FlatStyleFlat
TextUsers
button2Size580, 100
FlatStyleFlat
TextAccounts
button3Size580, 100
FlatStyleFlat
TextPermissions
label1TextCopyright 2022

Окно свойств кнопки в WinForms

Совет: свойства Size задаются как пара пикселей (ширина, высота). Для привязки размеров используйте Anchor/Dock при необходимости.

Создание кнопки настроек и списка тем

Для простого меню тем создайте отдельную кнопку «Themes» и три кнопки-переключателя для каждой темы. По умолчанию список кнопок тем скрыт и отображается по клику на кнопку настроек.

  1. Добавьте ещё одну кнопку на форму — она будет кнопкой настроек (Themes).
  2. Установите для неё свойства:
СвойствоНовое значение
NamebtnThemeSettings
FlatStyleFlat
Size200, 120
TextThemes

Свойства кнопки Themes

  1. Перетащите ещё три кнопки — по одной на каждую тему. Задайте для них свойства:
ЭлементСвойствоНовое значение
1-я кнопкаNamebtnLightTheme
BackColorWhiteSmoke
Size200, 80
FlatStyleFlat
TextLight
VisibleFalse
2-я кнопкаNamebtnNatureTheme
BackColorDarkSeaGreen
Size200, 80
FlatStyleFlat
TextNature
VisibleFalse
3-я кнопкаNamebtnDarkTheme
BackColorDimGray
ForeColorWhite
Size200, 80
FlatStyleFlat
TextDark
VisibleFalse

Свойства кнопок тем

  1. Дважды кликните по кнопке Themes — Visual Studio сгенерирует обработчик события Click. Внутри него переключайте видимость трёх кнопок тем:
private void btnThemeSettings_Click(object sender, EventArgs e)
{
    btnNatureTheme.Visible = !btnNatureTheme.Visible;
    btnLightTheme.Visible = !btnLightTheme.Visible;
    btnDarkTheme.Visible = !btnDarkTheme.Visible;
}
  1. Запустите приложение (зелёная кнопка Play). Кнопка запуска в Visual Studio
  2. По умолчанию кнопки тем скрыты. Приложение при запуске с скрытыми темами
  3. Нажимайте Themes для показа/скрытия вариантов. Отображение доступных тем в приложении

Как хранить палитры тем

Лучше хранить наборы цветов каждой темы в словарях. Это позволяет легко переиспользовать и обновлять значения.

  1. В файле Form1.cs, внутри класса Form определите enum, который перечисляет типы цветов, используемые в теме:
enum ThemeColor
{
    Primary,
    Secondary,
    Tertiary,
    Text
}
  1. Объявите три глобальных словаря, по одному на тему:
Dictionary Light = new Dictionary();
Dictionary Nature = new Dictionary();
Dictionary Dark = new Dictionary();
  1. В конструкторе формы инициализируйте словари значениями:
public Form1()
{
    InitializeComponent();

    // Инициализация словарей тем
    Light = new Dictionary() {
        { ThemeColor.Primary, Color.WhiteSmoke },
        { ThemeColor.Secondary, Color.Silver },
        { ThemeColor.Tertiary, Color.White },
        { ThemeColor.Text, Color.Black }
    };
    Nature = new Dictionary() {
        { ThemeColor.Primary, Color.DarkSeaGreen },
        { ThemeColor.Secondary, Color.AliceBlue },
        { ThemeColor.Tertiary, Color.Honeydew },
        { ThemeColor.Text, Color.Black }
    };
    Dark = new Dictionary() {
        { ThemeColor.Primary, Color.DimGray },
        { ThemeColor.Secondary, Color.DimGray },
        { ThemeColor.Tertiary, Color.Black },
        { ThemeColor.Text, Color.White }
    };

    // Установка темы по умолчанию
    ChangeTheme(Light[ThemeColor.Primary], Light[ThemeColor.Secondary], Light[ThemeColor.Tertiary]);
    ChangeTextColor(Light[ThemeColor.Text]);
}

Совет: если у вас много тем или сложные палитры, храните их в отдельных JSON-файлах или ресурсах и загружайте в словари при запуске.

Как применять тему к элементам интерфейса

Создайте функции, которые принимают цвета и применяют их к элементам формы.

private void ChangeTheme(Color primaryColor, Color secondaryColor, Color tertiaryColor)
{
    // Изменение фонового цвета кнопок и формы
    btnThemeSettings.BackColor = primaryColor;
    button1.BackColor = primaryColor;
    button2.BackColor = secondaryColor;
    button3.BackColor = secondaryColor;
    this.BackColor = tertiaryColor;
}

private void ChangeTextColor(Color textColor)
{
    // Изменение цвета текста
    button1.ForeColor = textColor;
    button2.ForeColor = textColor;
    button3.ForeColor = textColor;
    label1.ForeColor = textColor;
    btnThemeSettings.ForeColor = textColor;
}

Далее добавьте обработчики для кнопок тем:

private void btnLightTheme_Click(object sender, EventArgs e)
{
    ChangeTheme(Light[ThemeColor.Primary], Light[ThemeColor.Secondary], Light[ThemeColor.Tertiary]);
    ChangeTextColor(Light[ThemeColor.Text]);
}

private void btnNatureTheme_Click(object sender, EventArgs e)
{
    ChangeTheme(Nature[ThemeColor.Primary], Nature[ThemeColor.Secondary], Nature[ThemeColor.Tertiary]);
    ChangeTextColor(Nature[ThemeColor.Text]);
}

private void btnDarkTheme_Click(object sender, EventArgs e)
{
    ChangeTheme(Dark[ThemeColor.Primary], Dark[ThemeColor.Secondary], Dark[ThemeColor.Tertiary]);
    ChangeTextColor(Dark[ThemeColor.Text]);
}

Поведение по умолчанию и запуск

По умолчанию мы устанавливаем светлую тему в конструкторе формы (пример выше). Запустите приложение, и по умолчанию будет применена светлая палитра. Переключите темы для проверки. Приложение с применённой светлой темой

Приложение с природной темой

Приложение с тёмной темой

Расширения и лучшие практики

Ниже — набор рекомендаций и вариантов улучшения для более масштабируемых приложений.

Альтернативные подходы

  • Хранение тем в JSON/XML и динамическая загрузка. Это упрощает редактирование палитр без перекомпиляции.
  • Использование ресурса (ResX) или встроенных ресурсов для локализации цветов и иконок.
  • Применение паттерна «тема + рантайм-применение» через события: BroadcastThemeChanged, чтобы все компоненты реагировали централизованно.
  • Использование сторонних библиотек для теминга, если требуется сложная стилизация (иконки, шрифты, анимация).

Когда это не сработает из коробки

  • Кастомные контролы, которые рисуют себя вручную, могут игнорировать BackColor/ForeColor.
  • Компоненты, использующие аппаратное ускорение или отдельный рендерер, требуют отдельных обработчиков.
  • Если ваша форма содержит множество вложенных контейнеров, нужно рекурсивно проходить по Controls и менять цвета для всех дочерних элементов.

Пример рекурсивного применения:

private void ApplyColorsRecursive(Control parent, Color backColor, Color foreColor)
{
    foreach (Control c in parent.Controls)
    {
        c.BackColor = backColor;
        c.ForeColor = foreColor;
        if (c.HasChildren)
            ApplyColorsRecursive(c, backColor, foreColor);
    }
}

Сохранение выбранной темы между запусками

Самый простой вариант — сохранить имя темы в настройках пользователя (Properties.Settings) и применять на загрузке формы:

// Сохранение
Properties.Settings.Default.AppTheme = "Dark";
Properties.Settings.Default.Save();

// Загрузка
string savedTheme = Properties.Settings.Default.AppTheme;
if (savedTheme == "Dark") { /* применить Dark */ }

Замечание: в крупных проектах стоит использовать более устойчивый механизм конфигурации (например, JSON + версионирование схемы). Не забудьте обработать невалидные или отсутствующие значения.

Ментальные модели и эвристики

  • Разделяйте «палитру» и «применение» — палитра хранится отдельно, функции лишь читают её и применяют.
  • Подумайте о контрасте: проверяйте читаемость текста на фоне (WCAG-подходы, если нужна доступность).
  • Минимизируйте изменения свойств: меняйте только те свойства, которые действительно влияют на визуал.

Уровни зрелости решения

  1. Начальный: несколько кнопок, словари в коде, применение напрямую — подходит для прототипа.
  2. Средний: темы в ресурсах/файлах, сохранение настроек, рекурсивное применение цветов.
  3. Продвинутый: централизованный брокер тем, события подписки, поддержка кастомных контролов, доступность и тесты.

Чек-листы по ролям

Разработчик:

  • реализовать словари тем;
  • создать функции ChangeTheme, ChangeTextColor;
  • обеспечить рекурсивное применение для вложенных контролов;
  • добавить сохранение выбранной темы.

QA:

  • проверить видимость и переключение кнопок Themes;
  • проверить читаемость текста для каждой темы;
  • проверить корректность сохранения и загрузки темы между запусками;
  • протестировать поведение с кастомными контролами.

Дизайнер:

  • утвердить палитры для каждой темы;
  • проверить контраст и доступность;
  • предоставить набор иконок/изображений для тёмной и светлой тем.

Критерии приёмки

  • Пользователь может переключить тему через интерфейс.
  • Цвета применены ко всем основным контролам формы.
  • Выбранная тема сохраняется и восстанавливается при перезапуске.
  • Текст остаётся читаемым в каждой теме.

Тестовые сценарии

  1. Негативный: удалить или повредить сохранённый файл настроек — приложение должно упасть обратно к дефолту (Light).
  2. Позитивный: переключение всех трёх тем по очереди без перезапуска.
  3. Производительность: массовая форма с 200+ контролами — переключение темы должно происходить за приемлемое время (пользовательское наблюдение).

Шаблон быстрого аудита безопасности/конфиденциальности

  • Локальные настройки хранятся только на стороне клиента; при синхронизации с сервером используйте безопасный канал.
  • Не храните в теме чувствительные данные.

Пример расширения: тема с эффектами и иконками

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

Простая методология для внедрения тем в существующий проект

  1. Инвентаризация: найдите все визуальные элементы (кнопки, метки, панели, меню).
  2. Выделение цветов: определите Primary/Secondary/Tertiary/Text для каждой темы.
  3. Реализация: добавьте словари и функции применения.
  4. Привязка: подключите триггеры (кнопки или меню).
  5. Сохранение: добавьте хранение настроек пользователя.
  6. Тестирование: UI/QA, проверка доступности.

Диаграмма принятия решения (Mermaid)

flowchart TD
    A[Нужна простая смена цветов?] -->|Да| B[Словари + ChangeTheme]
    A -->|Нет, нужны иконки/шрифты| C[Пакет ресурсов + динамическая загрузка]
    C --> D[Создать ресурсную упаковку для тем]
    B --> E{Кастомные контролы?}
    E -->|Да| F[Добавить обработчики и события темы]
    E -->|Нет| G[Применять рекурсивно и сохранять]

Заключение

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

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

Краткое резюме и что делать дальше:

  • Начните с простого: словари + ChangeTheme/ChangeTextColor;
  • Добавьте сохранение в пользовательские настройки;
  • Расширяйте стратегию: ресурсы, события, централизованный менеджер тем;
  • Тестируйте контраст и поведение кастомных контролов.

Важно: цвета в примерах используются из стандартного пространства Color в Visual Studio. Подберите палитру, соответствующую бренду и требованиям доступности.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

OOBE в Windows 11: изменения и советы
Windows

OOBE в Windows 11: изменения и советы

Телеметрия Windows 10: ошибки и их решения
Windows 10

Телеметрия Windows 10: ошибки и их решения

Монитор не включается при загрузке Windows — решения
Техподдержка

Монитор не включается при загрузке Windows — решения

Wi‑Fi показывает «не защищён» — как исправить
Безопасность

Wi‑Fi показывает «не защищён» — как исправить

Как организовать пространство и событие в Gather
Онлайн встречи

Как организовать пространство и событие в Gather

Голос Siri в TikTok: быстро и просто
TikTok

Голос Siri в TikTok: быстро и просто