使用 WPF 为多个动态皮肤字典创建别名颜色定义

Z L*_*ang 5 c# wpf xaml themes dynamicresource

我正在尝试在大型 WPF 应用程序中设置主题框架。目前我们找到的解决方案是为每个调色板创建单独的 .xaml 文件,如下所示:

<LightColors.xaml>
<Color x:Key="MainPanelColor">Aqua</Color>
<Color x:Key="MainItemColor">Orange</Color>
<SolidColorBrush x:Key="MainPanelBrush" Color="{StaticResource MainPanelColor}" />
<SolidColorBrush x:Key="MainItemBrush"  Color="{StaticResource MainItemColor}" />
Run Code Online (Sandbox Code Playgroud)

然后 UI 会像这样引用这些项目:

<Textblock Foreground="{DynamicResource MainItemBrush}"/>
Run Code Online (Sandbox Code Playgroud)

在 C# 中,调色板在运行时会更改。该主题框架完成了允许在运行时更改主题的任务。

问题:我想在 UI 和颜色之间创建一个层,以便调色板颜色可以链接到整个 UI 中使用的大量颜色定义。我发现接近有效的唯一解决方案是添加如下文件:

<ColorDefinitions.xaml>
<DynamicResource x:Key="Textblock_SetupPage_Foreground" ResourceKey="MainItemBrush" />
<DynamicResource x:Key="SecondDefinition" ResourceKey="MainItemBrush" />
Run Code Online (Sandbox Code Playgroud)

并在 UI 中引用这个新资源,如下所示:

<Textblock Foreground="{StaticResource Textblock_SetupPage_Foreground}" />
Run Code Online (Sandbox Code Playgroud)

不过,这个解决方案并不能完全发挥作用。它只允许单个 UI 元素使用 DynamicResources 之一,例如“Textblock_SetupPage_Foreground”,并且将 Textblock 引用更改为 DynamicResource 会产生错误。我怎样才能完成这个任务?

小智 2

不太确定这是否能解决您的问题,但我可以向您展示如何在 LOB 中实现换肤。该示例解决方案由两个程序集和示例应用程序组成。

\n\n

MyCustomControlLibrary 定义颜色和画笔以及示例自定义控件。颜色和画笔可以进一步分离为额外的组件。

\n\n

MySkinsLibrary 定义外观并使用 MyControlLibrary 中的定义(资源)。

\n\n

WpfSkinTestApp 使用皮肤并间接使用 MyCostumControlLibrary。

\n\n

WPFS剥皮测试解决方案

\n\n

颜色.xaml:

\n\n
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n                xmlns:local="clr-namespace:MyCustomControlLibrary">\n<Color x:Key="MyDarkColor">#FF123456</Color>\n<Color x:Key="MyLightColor">#FF456789</Color>\n<Color x:Key="MyNeutralColor">#FF666666</Color>\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n

画笔.xaml

\n\n
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n                xmlns:local="clr-namespace:MyCustomControlLibrary">\n<ResourceDictionary.MergedDictionaries>\n    <ResourceDictionary Source="/MyCustomControlLibrary;component/ResourceDictionaries/Colors.xaml"/>\n</ResourceDictionary.MergedDictionaries>\n<SolidColorBrush x:Key="MyDarkColorBrush" Color="{StaticResource MyDarkColor}"/>\n<SolidColorBrush x:Key="MyLightColorBrush" Color="{StaticResource MyLightColor}"/>\n<SolidColorBrush x:Key="MyNeutralColorBrush" Color="{StaticResource MyNeutralColor}"/>\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n

通用.xaml

\n\n
<ResourceDictionary\nxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\nxmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\nxmlns:local="clr-namespace:MyCustomControlLibrary">\n<ResourceDictionary.MergedDictionaries>\n    <ResourceDictionary Source="/MyCustomControlLibrary;component/ResourceDictionaries/Brushes.xaml"/>\n</ResourceDictionary.MergedDictionaries>\n<Style TargetType="{x:Type local:MyCustomControl}">\n    <Setter Property="Background" Value="{StaticResource MyNeutralColorBrush}"/>\n    <Setter Property="BorderBrush" Value="White"/>\n    <Setter Property="BorderThickness" Value="6"/>\n    <Setter Property="Template">\n        <Setter.Value>\n            <ControlTemplate TargetType="{x:Type local:MyCustomControl}">\n                <Border Background="{TemplateBinding Background}"\n                        BorderBrush="{TemplateBinding BorderBrush}"\n                        BorderThickness="{TemplateBinding BorderThickness}">\n\n                </Border>\n            </ControlTemplate>\n        </Setter.Value>\n    </Setter>\n</Style>\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n

深色皮肤.xaml

\n\n
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n                xmlns:local="clr-namespace:MySkinsLibrary.Skins"\n                xmlns:customControls="clr-namespace:MyCustomControlLibrary;assembly=MyCustomControlLibrary">\n<ResourceDictionary.MergedDictionaries>\n    <ResourceDictionary Source="/MyCustomControlLibrary;component/Themes/Generic.xaml"/>\n</ResourceDictionary.MergedDictionaries>\n\n<Style x:Key="MyTextBlockStyle" TargetType="TextBlock">\n    <Setter Property="Background" Value="Gray"/>\n    <Setter Property="Foreground" Value="{StaticResource MyDarkColorBrush}"/>\n</Style>\n\n<Style x:Key="MyCustomControlStyle" TargetType="{x:Type customControls:MyCustomControl}" BasedOn="{StaticResource {x:Type customControls:MyCustomControl}}">\n    <Setter Property="Background" Value="{StaticResource MyDarkColorBrush}"/>\n</Style>\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n

LightSkin.xaml

\n\n
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n                xmlns:local="clr-namespace:MySkinsLibrary.Skins"\n                xmlns:customControls="clr-namespace:MyCustomControlLibrary;assembly=MyCustomControlLibrary">\n<ResourceDictionary.MergedDictionaries>\n    <ResourceDictionary Source="/MyCustomControlLibrary;component/Themes/Generic.xaml"/>\n</ResourceDictionary.MergedDictionaries>\n\n<Style x:Key="MyTextBlockStyle" TargetType="TextBlock">\n    <Setter Property="Background" Value="Gray"/>\n    <Setter Property="Foreground" Value="{StaticResource MyLightColorBrush}"/>\n</Style>\n\n<Style x:Key="MyCustomControlStyle" TargetType="{x:Type customControls:MyCustomControl}" BasedOn="{StaticResource {x:Type customControls:MyCustomControl}}">\n    <Setter Property="Background" Value="{StaticResource MyLightColorBrush}"/>\n</Style>\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n

在您的应用程序中,您可以在 app.xaml 中使用不同的外观,如下所示:\n(出于设计目的)

\n\n
<Application x:Class="WpfSkinTestApp.App"\n         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n         xmlns:local="clr-namespace:WpfSkinTestApp"\n         StartupUri="MainWindow.xaml">\n<Application.Resources>\n    <ResourceDictionary>\n        <ResourceDictionary.MergedDictionaries>\n            <ResourceDictionary Source="pack://application:,,,/MySkinsLibrary;component/Skins/LightSkin.xaml"/>\n        </ResourceDictionary.MergedDictionaries>\n    </ResourceDictionary>\n</Application.Resources>\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n

并在运行时更改它,例如这样:

\n\n
private void RadioButton_Checked(object sender, RoutedEventArgs e)\n    {\n        string skinName = "LightSkin";\n\n        if (((RadioButton)sender).Name == "DarkSkin")\n        {\n            skinName = "DarkSkin";\n        }\n\n        ResourceDictionary resources = new ResourceDictionary();\n        resources.Source = new Uri($"pack://application:,,,/MySkinsLibrary;component/Skins/{skinName}.xaml");\n        Application.Current.Resources = resources;\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

为了完整性,这是测试应用程序的主窗口:

\n\n
<Window x:Class="WpfSkinTestApp.MainWindow"\n    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\n    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\n    xmlns:customControls="clr-namespace:MyCustomControlLibrary;assembly=MyCustomControlLibrary"\n    xmlns:local="clr-namespace:WpfSkinTestApp"\n    mc:Ignorable="d"\n    Title="MainWindow" Height="350" Width="525"\n    Background="{StaticResource MyNeutralColorBrush}">\n<Grid>\n    <Grid.ColumnDefinitions>\n        <ColumnDefinition/>\n        <ColumnDefinition/>\n        <ColumnDefinition/>\n    </Grid.ColumnDefinitions>\n    <Grid.RowDefinitions>\n        <RowDefinition/>\n        <RowDefinition Height="Auto"/>\n        <RowDefinition/>\n        <RowDefinition/>\n    </Grid.RowDefinitions>\n    <TextBlock Grid.Column="1"\n               Grid.Row="1"\n               Text="Example Colors"\n               Style="{DynamicResource MyTextBlockStyle}"/>\n    <customControls:MyCustomControl Grid.Column="1"\n                                    Grid.Row="2"\n                                    Style="{DynamicResource MyCustomControlStyle}"/>\n    <StackPanel Grid.Column="2"\n                Grid.Row="2"\n                Margin="24"                    >\n        <RadioButton x:Name="LightSkin" GroupName="1" Content="Light Skin" IsChecked="True" Checked="RadioButton_Checked"/>\n        <RadioButton x:Name="DarkSkin" GroupName="1" Content="Dark Skin" Checked="RadioButton_Checked"/>\n    </StackPanel>\n</Grid>\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n

如果这就是您\xc2\xb4 正在寻找的东西,请告诉我。

\n