{ThemeResource ResourceName}
<ResourceDictionary> <ResourceDictionary.ThemeDictionaries> <ResourceDictionary x:Key="Light"> <SolidColorBrush x:Key="MyBackgroundBrush" Color="#FFFFFFFF" /> </ResourceDictionary> <ResourceDictionary x:Key="Dark"> <SolidColorBrush x:Key="MyBackgroundBrush " Color="#FF232323" /> </ResourceDictionary> <ResourceDictionary x:Key="HighContrast"> <SolidColorBrush x:Key="MyBackgroundBrush " Color="#FF000000" /> </ResourceDictionary> </ResourceDictionary.ThemeDictionaries> </ResourceDictionary>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="BackgroundBrush" Color="#FF1A1A1A" /> <SolidColorBrush x:Key="ForegroundBrush" Color="White" /> <SolidColorBrush x:Key="ChromeBrush" Color="#FF232323" /> </ResourceDictionary>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="BackgroundBrush" Color="White" /> <SolidColorBrush x:Key="ForegroundBrush" Color="Black" /> <SolidColorBrush x:Key="ChromeBrush" Color="#FFBFBFBF" /> </ResourceDictionary>
public sealed class ThemeManager : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
public const string DarkThemePath = "ms-appx:///Themes/Theme.Dark.xaml"; public const string LightThemePath = "ms-appx:///Themes/Theme.Light.xaml";
private ResourceDictionary _currentThemeDictionary;
public string CurrentTheme { get; private set; } public Brush BackgroundBrush => _currentThemeDictionary[nameof(BackgroundBrush)] as Brush; public Brush ChromeBrush => _currentThemeDictionary[nameof(ChromeBrush)] as Brush; public Brush ForegroundBrush => _currentThemeDictionary[nameof(ForegroundBrush)] as Brush;
private void RaisePropertyChanged() { OnPropertyChanged(nameof(BackgroundBrush)); OnPropertyChanged(nameof(ChromeBrush)); OnPropertyChanged(nameof(ForegroundBrush)); OnPropertyChanged(nameof(CurrentTheme)); }
public void LoadTheme(string path) { _currentThemeDictionary = new ResourceDictionary(); App.LoadComponent(_currentThemeDictionary, new Uri(path)); CurrentTheme = Path.GetFileNameWithoutExtension(path); RaisePropertyChanged(); } public async Task LoadThemeFromFile(StorageFile file) { string xaml = await FileIO.ReadTextAsync(file); _currentThemeDictionary = XamlReader.Load(xaml) as ResourceDictionary; CurrentTheme = Path.GetFileNameWithoutExtension(file.Path); RaisePropertyChanged(); }
public ThemeManager() { LoadTheme(DarkThemePath); }
<Application x:Class="UwpThemeManager.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UwpThemeManager"> <Application.Resources> <ResourceDictionary> <local:ThemeManager x:Key="ThemeManager" /> </ResourceDictionary> </Application.Resources> </Application>
public static ThemeManager ThemeManager => (ThemeManager)App.Current.Resources["ThemeManager"];
using System; using System.ComponentModel; using System.IO; using System.Threading.Tasks; using Windows.Storage; using Windows.UI.Xaml; using Windows.UI.Xaml.Markup; using Windows.UI.Xaml.Media; namespace UwpThemeManager { public sealed class ThemeManager : INotifyPropertyChanged { public const string DarkThemePath = "ms-appx:///Themes/Theme.Dark.xaml"; public const string LightThemePath = "ms-appx:///Themes/Theme.Light.xaml"; public event PropertyChangedEventHandler PropertyChanged; public ThemeManager() { LoadTheme(DarkThemePath); } public string CurrentTheme { get; private set; } public Brush BackgroundBrush => _currentThemeDictionary[nameof(BackgroundBrush)] as Brush; public Brush ChromeBrush => _currentThemeDictionary[nameof(ChromeBrush)] as Brush; public Brush ForegroundBrush => _currentThemeDictionary[nameof(ForegroundBrush)] as Brush; public void LoadTheme(string path) { _currentThemeDictionary = new ResourceDictionary(); App.LoadComponent(_currentThemeDictionary, new Uri(path)); CurrentTheme = Path.GetFileNameWithoutExtension(path); RaisePropertyChanged(); } public async Task LoadThemeFromFile(StorageFile file) { string xaml = await FileIO.ReadTextAsync(file); _currentThemeDictionary = XamlReader.Load(xaml) as ResourceDictionary; CurrentTheme = Path.GetFileNameWithoutExtension(file.Path); RaisePropertyChanged(); } private void RaisePropertyChanged() { OnPropertyChanged(nameof(BackgroundBrush)); OnPropertyChanged(nameof(ChromeBrush)); OnPropertyChanged(nameof(ForegroundBrush)); OnPropertyChanged(nameof(CurrentTheme)); } private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); private ResourceDictionary _currentThemeDictionary; } }
<Rectangle Fill="{Binding BackgroundBrush, Source={StaticResource ThemeManager}}"/>
private void DarkThemeButton_Click(object sender, RoutedEventArgs e) => App.ThemeManager.LoadTheme(ThemeManager.DarkThemePath); private void LightThemeButton_Click(object sender, RoutedEventArgs e) => App.ThemeManager.LoadTheme(ThemeManager.LightThemePath); private async void CustomThemeButton_Click(object sender, RoutedEventArgs e) { var picker = new FileOpenPicker(); picker.FileTypeFilter.Add(".xaml"); var file = await picker.PickSingleFileAsync(); if (file != null) { try { await App.ThemeManager.LoadThemeFromFile(file); } catch (Exception ex) { var msg = new MessageDialog(ex.ToString(), ""); await msg.ShowAsync(); } } }
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="BackgroundBrush" Color="#FF1A1A1A" /> <SolidColorBrush x:Key="ForegroundBrush" Color="White" /> <SolidColorBrush x:Key="ChromeBrush" Color="#FF5A0000" /> </ResourceDictionary>
<Page x:Class="UwpThemeManager.MainPage1" 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" mc:Ignorable="d"> <Grid Background="{Binding BackgroundBrush, Source={StaticResource ThemeManager}}"> <Grid.RowDefinitions> <RowDefinition Height="48" /> <RowDefinition /> </Grid.RowDefinitions> <Border Background="{Binding ChromeBrush, Source={StaticResource ThemeManager}}"> <TextBlock Text="{Binding CurrentTheme, Source={StaticResource ThemeManager}}" Foreground="{Binding ForegroundBrush, Source={StaticResource ThemeManager}}" Style="{StaticResource SubtitleTextBlockStyle}" VerticalAlignment="Center" Margin="12,0,0,0" /> </Border> <StackPanel Grid.Row="1" HorizontalAlignment="Center"> <Button Content="Dark theme" Background="{Binding ChromeBrush, Source={StaticResource ThemeManager}}" Foreground="{Binding ForegroundBrush, Source={StaticResource ThemeManager}}" Margin="0,12,0,0" HorizontalAlignment="Stretch" Click="DarkThemeButton_Click" /> <Button Content="Light Theme" Background="{Binding ChromeBrush, Source={StaticResource ThemeManager}}" Foreground="{Binding ForegroundBrush, Source={StaticResource ThemeManager}}" Margin="0,12,0,0" HorizontalAlignment="Stretch" Click="LightThemeButton_Click" /> <Button Content="Custom theme" Background="{Binding ChromeBrush, Source={StaticResource ThemeManager}}" Foreground="{Binding ForegroundBrush, Source={StaticResource ThemeManager}}" Margin="0,12,0,0" HorizontalAlignment="Stretch" Click="CustomThemeButton_Click" /> </StackPanel> </Grid> </Page>
Attached Property. This is Dependency Property, which is not declared in the class of the object for which it will be used, but behaves as if it were part of it. It is declared in a separate class, has getter and setter in the form of static methods. You can add a handler to the PropertyChanged event.
Visual Studio has a special preset (code snippet) for the Attached Dependency Property, which is available by typing propa and pressing Tab.
using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Data; namespace UwpThemeManager.BindingHelpers { public static class BackgroundBindingHelper { public static string GetBackground(DependencyObject obj) => (string)obj.GetValue(BackgroundProperty); public static void SetBackground(DependencyObject obj, string value) => obj.SetValue(BackgroundProperty, value); public static readonly DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached("Background", typeof(string), typeof(BackgroundBindingHelper), new PropertyMetadata(null, BackgroundPathPropertyChanged)); private static void BackgroundPathPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var propertyPath = e.NewValue as string; if (propertyPath != null) { var backgroundproperty = Control.BackgroundProperty; BindingOperations.SetBinding(obj, backgroundproperty, new Binding { Path = new PropertyPath(propertyPath), Source = App.ThemeManager }); } } } }
using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Data; namespace UwpThemeManager.BindingHelpers { public static class ForegroundBindingHelper { public static string GetForeground(DependencyObject obj) => (string)obj.GetValue(ForegroundProperty); public static void SetForeground(DependencyObject obj, string value) => obj.SetValue(ForegroundProperty, value); public static readonly DependencyProperty ForegroundProperty = DependencyProperty.RegisterAttached("Foreground", typeof(string), typeof(ForegroundBindingHelper), new PropertyMetadata(null, ForegroundPathPropertyChanged)); private static void ForegroundPathPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var propertyPath = e.NewValue as string; if (propertyPath != null) { var backgroundproperty = Control.ForegroundProperty; BindingOperations.SetBinding(obj, backgroundproperty, new Binding { Path = new PropertyPath(propertyPath), Source = App.ThemeManager }); } } } }
<Page.Resources> <Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="binding:BackgroundBindingHelper.Background" Value="ChromeBrush" /> <Setter Property="binding:ForegroundBindingHelper.Foreground" Value="ForegroundBrush" /> <Setter Property="Margin" Value="0,12,0,0" /> <Setter Property="HorizontalAlignment" Value="Stretch"/> </Style> </Page.Resources>
<Page x:Class="UwpThemeManager.MainPage" 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:binding="using:UwpThemeManager.BindingHelpers" mc:Ignorable="d"> <Page.Resources> <Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="binding:BackgroundBindingHelper.Background" Value="ChromeBrush" /> <Setter Property="binding:ForegroundBindingHelper.Foreground" Value="ForegroundBrush" /> <Setter Property="Margin" Value="0,12,0,0" /> <Setter Property="HorizontalAlignment" Value="Stretch"/> </Style> </Page.Resources> <Grid Background="{Binding BackgroundBrush, Source={StaticResource ThemeManager}}"> <Grid.RowDefinitions> <RowDefinition Height="48" /> <RowDefinition /> </Grid.RowDefinitions> <Border Background="{Binding ChromeBrush, Source={StaticResource ThemeManager}}"> <TextBlock Text="{Binding CurrentTheme, Source={StaticResource ThemeManager}}" Foreground="{Binding ForegroundBrush, Source={StaticResource ThemeManager}}" Style="{StaticResource SubtitleTextBlockStyle}" VerticalAlignment="Center" Margin="12,0,0,0" /> </Border> <StackPanel Grid.Row="1" HorizontalAlignment="Center"> <Button Content="Dark theme" Style="{StaticResource ButtonStyle}" Click="DarkThemeButton_Click" /> <Button Content="Light Theme" Style="{StaticResource ButtonStyle}" Click="LightThemeButton_Click" /> <Button Content="Custom theme" Style="{StaticResource ButtonStyle}" Click="CustomThemeButton_Click" /> </StackPanel> </Grid> </Page>
Source: https://habr.com/ru/post/336054/
All Articles