WPF中切换主题功能

在现代 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;
}

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

发布时间:2025-05-08
其他阅读

新版本.Net关于Process.Start的问题

.Net 开发中,试用 Process.Start() 来启动一个新进程,当我们传入的是具体文件或者链接的时候,系统也会根据默认打开方式打开对应的进程。但是在新版本的 .Net 中,试用 Process.Start() 来打开文件或者链接的时候,会抛出 System.ComponentModel.Win32Exception 的错误,提示系统找不到指定的文件。

查看原文

WPF中切换主题功能

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

查看原文

WPF打包成单文件

在开发WPF程序时,有时我们需要把整个软件打包成一个文件,这样可以方便分发,本文将会介绍怎么把WPF打包成单文件形式。

查看原文

如何查看系统端口占用

在web开发中,时常会遇到开发的应用无法启动,这种情况一般是由于当前监听端口已经被别的应用先行占用监听了。本文就 Windows 和 Linux 介绍一下查看端口占用程序。

查看原文

WPF托盘运行

本文介绍如何将WPF应用最小化到托盘,窗口关闭后进程仍然运行的方法。

查看原文