Обновление стилей в WPF

Задача стоит сделать ночную тему в приложении, с возможностью переключать её "на горячую".

private void SwitchTheme()
{
    switch (AppState)
    {
        case AppModeEnum.DayEdit:
            ChangeTheme(new Uri("View/Style/StyleDictionaryDayEdit.xaml", UriKind.Relative));
            break;
        case AppModeEnum.Night:
            ChangeTheme(new Uri("View/Style/StyleDictionaryNight.xaml", UriKind.Relative));

    }
}

    private void ChangeTheme(Uri themeuri)
    {
        ResourceDictionary Theme = new ResourceDictionary() { Source = themeuri };
        App.Current.Resources.Clear();
        App.Current.Resources.MergedDictionaries.Add(Theme);
    }

Сделал через подмену ресурсов приложения. Но столкнулся со следующей проблемой, неименованные стили таким способом нормально подменяются, но стили у которых задан x:Key почему-то нет. Но при этом новые окна отрисовываются уже с правильными стилями, даже если Key задан. Задача заставить перерисоваться контролы у которых не общий стиль, в уже открытых окнах. Как-то это возможно сделать? UpdateDefaultStyle и UpdateLayout не помогает. Помогает только закрыть и открыть окно, но для основного окна приложения это не вариант.


По итогу проблему удалось решить благодаря помощи @xellan, за что ему огромное спасибо. Он предоставил замечательные примеры использования паттерна MVVM, а так же указал на главную ошибку.

Вот его примеры :

https://github.com/xellans/LearnMvvm

https://github.com/INexteR/NewTrade/tree/main

И так, вот к чему я пришёл по итогу :

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

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="View/Style/StyleDictionaryDay.xaml"/>
            <ResourceDictionary Source="View/Style/MainDictionary.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>        
</Application.Resources>

В стилях в словарях, цвета были заданы в качестве динамических ресурсов :

<Setter Property="BorderBrush"
     Value="{DynamicResource TextBrush}"/>

На контролах стили так же были заданы не как статические, а как динамические ресурсы :

<Button Content="  Редактировать устройство                                          
        Style="{DynamicResource SupWindowButton}"/>

А дальше любым удобным способом дёргаем метод который удалит из словаря стиля текущий словарь с цветами и добавит нужный :

//Удаляем текущий стиль, найдя его каким-нибудь способом. Я тут нахожу исходя их того, что все словари цветов у меня содержат в названии часть "ColorTheme"

var dictionariesToRemove = Application.Current.Resources.MergedDictionaries
    .Where(d => d.Source != null && d.Source.OriginalString.Contains("ColorTheme"))
    .ToList();
foreach (var dictionary in dictionariesToRemove)                        
  Application.Current.Resources.MergedDictionaries.Remove(dictionary);

//Добавляем в MergedDictionaries нашего приложения словарь с новой цветовой схемой

    string directory = AppStateToPathString(FlagsManager.AppState);
Application.Current.Resources.MergedDictionaries
.Add(new ResourceDictionary() { Source = new Uri(directory, UriKind.Relative) }); 

Вот пример, где максимально просто реализовал данный подход: https://github.com/spasskiy/WpfStylesTrain

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


Ответы (0 шт):