Обновление стилей в 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
Теперь можно спокойно переключать цветовые схемы сразу во всём приложении, а при необходимости смены цветов, всё это делается в одном месте.