WPF中切换主题功能

发布时间:2025-05-08

在现代 Windows 系统中,系统提供了亮色主题和暗色主题,Windows 自带的应用程序都已经适配该功能。本文介绍在使用 WPF 构建 Windows 窗口应用时怎么实现主题切换。

资源字典

在 WPF 中,资源是可在应用程序中的不同位置重复使用的对象,资源可以存储在 XAML 文件中,该文件称为资源字典文件,该文件没有配套的后端 cs 代码,使用纯粹的 xml 进行定义。在切换主题时,我们就需要用到资源文件。

颜色系统

首先,整理出整个应用的颜色系统,包含了边框颜色,背景颜色,主色,特殊色。如下所示:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Test"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <SolidColorBrush x:Key="BorderBrush" Color="#E5E5E5" />
    <SolidColorBrush x:Key="PageBackgroundBrush" Color="#F9F9F9" />
    <SolidColorBrush x:Key="PrimaryBrush" Color="#0D76F5" />
    <SolidColorBrush x:Key="DangerBrush" Color="#FF1214" />
</ResourceDictionary>

将文件保存为 Light.xaml,在同目录下再创建 Dark.xaml 文件,颜色字段与 Light.xaml 中一致,颜色值改成暗色主题相关即可。如下所示:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Test"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <SolidColorBrush x:Key="BorderBrush" Color="#4D4D4D" />
    <SolidColorBrush x:Key="PageBackgroundBrush" Color="#1C1C1F" />
    <SolidColorBrush x:Key="PrimaryBrush" Color="#0D76F5" />
    <SolidColorBrush x:Key="DangerBrush" Color="#FF1214" />
</ResourceDictionary>

在App.xaml中引入默认主题对应的资源,默认使用两色主题,这里引入Light.xaml。如下所示:

<Application
    x:Class="Test.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Test">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!--使用相对位置引入资源字典文件-->
                <ResourceDictionary Source="Colors/LightColor.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

颜色切换

将颜色应用到窗口程序中,设置窗口的背景颜色和卡片的边框颜色。

<Window
    x:Class="Test.MainWindow"
    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:local="clr-namespace:Test"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="400"
    Height="400"
    Background="{DynamicResource PageBackgroundBrush}"
    mc:Ignorable="d">
    <Grid>
        <StackPanel>
            <TextBlock
                FontSize="24"
                Foreground="{DynamicResource DangerBrush}"
                Text="Hello, World!" />
            <Button
                Margin="5"
                Padding="10"
                Background="{DynamicResource PrimaryBrush}"
                Click="Button_Click"
                Content="切换主题"
                Foreground="White" />
            <Border
                Width="100"
                Height="100"
                Margin="10"
                BorderBrush="{DynamicResource BorderBrush}"
                BorderThickness="1" />
        </StackPanel>
    </Grid>
</Window>

在按钮的响应事件中替换对应的资源字典文件,将原来的资源字典文件移除即可。

private void Button_Click(object sender, RoutedEventArgs e)
{
    List<ResourceDictionary> dictionaryList = new List<ResourceDictionary>();
    foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries)
    {
        dictionaryList.Add(dictionary);
    }
    ResourceDictionary defaults = dictionaryList.FirstOrDefault(d => d.Source.OriginalString.EndsWith("Color.xaml"));
    Application.Current.Resources.MergedDictionaries.Remove(defaults);
    string requestedColor = $@"pack://application:,,,/Colors/{(isDark ? "Light" : "Dark")}Color.xaml";
    ResourceDictionary resourceDictionary = new ResourceDictionary() { Source = new Uri(requestedColor) };
    Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
    isDark = !isDark;
}

最后运行起来,点击“切换主题”按钮即可看到效果。

其他阅读

命令行打包.net项目

.net 日常开发中,我们接触最多的就是 Visual Studio ,它是微软为了 .net 平台专门打造的 IDE (集成开发环境),为整个 .net 平台开发带来了无与伦比的图形化体验,但是有时候,我们也会遇到需要通过命令行来生成 .net 项目的情况,本文会介绍几种命令行打包的姿势。

查看原文

JSON是什么

在现代化 Web 应用开发中,广泛使用一种名为 JSON 的数据交换格式。JSON 是一种轻量级数据交换格式,在不同系统之间提供标准且高效的数据交换。

查看原文

WPF中CornerRadius是什么属性

在WPF中,CornerRadius 属性我们经常需要使用到,它的作用是用来设置控件的四个圆角,在 BorderButton 等控件中使用。等同于 css 中的 border-radius 设置。

查看原文

Unity控制台打印彩色日志

在 Unity 开发过程中,我们经常需要使用 Debug.Log 来输出调试信息。但是在繁杂的控制台信息中,一些重要的信息很容易就被忽略。使用彩色日志可以大幅提升Unity开发中的调试效率。

查看原文

删除 Office 中毒瘤:Office Plus 插件

在某次更新之后,Office Plus 插件就会自动添加到 Word、Excel、PowerPoint 中,在我看来算是一个毒瘤,极大地拖慢了 Office 的运行,本文教大家怎么删除 Office Plus 这个毒瘤。

查看原文