Whp.WPF.Themes 0.0.3

dotnet add package Whp.WPF.Themes --version 0.0.3
                    
NuGet\Install-Package Whp.WPF.Themes -Version 0.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Whp.WPF.Themes" Version="0.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Whp.WPF.Themes" Version="0.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Whp.WPF.Themes" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Whp.WPF.Themes --version 0.0.3
                    
#r "nuget: Whp.WPF.Themes, 0.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Whp.WPF.Themes@0.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Whp.WPF.Themes&version=0.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Whp.WPF.Themes&version=0.0.3
                    
Install as a Cake Tool

在 WPF 桌面应用开发中如何使用?

前提条件

  • 引用 Whp.WPF.Themes 命名空间。

  • 准备好资源文件夹,包含:主题、样式、字体等 XAML 文件以及自定义的资源目录类。资源文件夹结构示例:

    Resources/
    ├── Themes/
    │   ├── Theme.Fonts.xaml
    │   ├── Theme.Colors.xaml
    │   ├── Theme.Dark.xaml
    │   ├── Theme.Light.xaml
    │   └── ...
    ├── Styles/
    │   ├── Common.xaml
    │   ├── TextBlock.xaml
    │   ├── Button.xaml
    │   ├── TextBox.xaml
    │   └── ...
    └── AutoCadThemeCatalog.cs
    

    ⚠️ 资源文件中所有 XAML 文件的 Build Action 必须设为 Page,否则 pack:// URI 加载会失败并抛出 XamlParseException。

1. 主题检测器

  • 推荐使用 Whp.WPF.Themes.Detection 提供的 WindowsThemeDetector 类。
  • 自定义创建了一个名为主题检测器的类,继承自 IThemeDetector 接口,并实现 GetSystemTheme() 和 ObserveSystemTheme() 方法。

2. 定义桌面应用的资源目录

创建资源目录类,告诉引擎你的 XAML 资源文件在哪里、按什么顺序加载; 推荐继承 ThemeResourcesBase:

using System.Reflection;
using Whp.WPF.Themes;

public class DesktopThemeCatalog : ThemeResourcesBase
{
     public override string AssemblyName => Assembly.GetExecutingAssembly().GetName().Name;

     public override IReadOnlyList<string> GetPaths(ThemeMode mode)
     {
         var themeFile = mode switch
        {
            ThemeMode.Dark  => "Resources/Themes/Theme.Dark.xaml",
            ThemeMode.Light => "Resources/Themes/Theme.Light.xaml",
            _               => "Resources/Themes/Theme.Light.xaml"
        };

        return new List<string>
        {
            "Resources/Themes/Theme.Fonts.xaml",
            "Resources/Themes/Theme.Colors.xaml",
            themeFile,
            "Resources/Styles/Common.xaml",
            "Resources/Styles/TextBlock.xaml",
            "Resources/Styles/Button.xaml",
            "Resources/Styles/TextBox.xaml",
            "Resources/Styles/ComboBox.xaml",
            "Resources/Styles/CheckBox.xaml",
            "Resources/Styles/RadioButton.xaml",
            "Resources/Styles/GroupBox.xaml",
            "Resources/Styles/Window.xaml"
        };
     }
}
路径规则:
  • 使用 / 分隔(pack URI 规范),不要用 \。
  • 路径相对程序集根,不能带前导 /,大小写敏感。
  • 顺序即加载顺序,后加载覆盖先加载的同名 Key。
  • 推荐顺序:基础变量(Fonts / Colors)→ 主题(Dark / Light)→ 控件样式 → 自定义覆盖。
  • ThemeMode 目前只有 Light / Dark,建议用 switch 而非三元表达式,便于将来扩展。
实例化建议:

使用静态单例复用 catalog,避免每次 Apply 都 new 一个实例(丢失内部缓存):

internal static readonly AutoCadThemeCatalog Catalog = new();

3. 在应用启动时初始化引擎

在 App.xaml.cs 的 OnStartup 中完成一次性配置。引擎作为静态单例,全局共享。

using System.Windows;
using Whp.WPF.Themes;
using Whp.WPF.Themes.Detection;

public partial class App : Application
{
    /// <summary>全局共享的主题引擎。</summary>
    internal static ThemeManager Theme { get; private set; } = null!;
    
    /// <summary>全局共享的资源目录单例。</summary>
    internal static readonly DesktopThemeCatalog Catalog = new();
    
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        // 1) 创建持久化提供者(可选)。
        //    不传 = 纯内存状态,每次启动都跟随 CAD;
        //    传入 = 记住用户上次选择的 ThemeOption。
        //
        // ⚠️ 持久化文件不要写入 Program Files,应放在:
        //    - %AppData%\MyCadPlugin\theme.json
        //    - 或插件自身的用户配置目录
        IThemeSettingsProvider settings =
            new JsonThemeSettingsProvider(
                System.IO.Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                    "MyCadPlugin",
                    "theme.json"));

        // 2) 创建引擎
        Theme = new ThemeManager(settings);

        // 3) 注册 Windows 桌面主题检测器
        Theme.Register(new WindowsThemeDetector());

        // 4) 可选:监听主题变化做额外业务逻辑
        Theme.ThemeChanged += (s, e) =>
        {
            System.Diagnostics.Debug.WriteLine(
                $"[App] Theme: {e.OldMode} → {e.NewMode}");

            // 在此更新非 WPF 资源(图标、原生控件等),见第 9 节
        };
    }
       
    protected override void OnExit(ExitEventArgs e)
    {
        Theme?.Dispose();
        base.OnExit(e);
    }
}

4. 在 WPF 窗口/用户控件中应用主题

using System.Windows;
using Whp.WPF.Themes;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        // 一行代码应用主题:
        // FollowSystem = 跟随 Windows 深浅色设置自动切换
        App.Theme.Apply(this, App.Catalog, ThemeOption.FollowSystem);

        // 之后用户在 Windows 设置里切换"应用模式"时,
        // 此窗口会自动刷新,无需手动处理。
    }
}
注意事项:
  • 调用时机:在 InitializeComponent() 之后 调用。
  • 新窗口:每个新窗口/面板在构造时调用一次 Apply 即可,关闭后引擎会自动从跟踪列表移除(弱引用 + Unloaded 事件)。

运行时切换主题

典型场景:设置页让用户选择浅色 / 深色 / 跟随系统。

// 读取当前选项
ThemeOption current = App.Theme.SelectedOption;

// 用户点击"深色"
App.Theme.SelectedOption = ThemeOption.Dark;
// → 自动持久化 + 刷新所有已 Apply 的窗口 + 触发 ThemeChanged 事件

// 用户点击"跟随系统"
App.Theme.SelectedOption = ThemeOption.FollowSystem;
// → 立即取 Windows 当前设置,并开始跟随系统变化
引擎自动完成:
  • 将新选项写入 IThemeSettingsProvider;
  • 重新解析生效主题;
  • 刷新所有已注册的目标元素;
  • 触发 ThemeChanged 事件。
Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed.  net10.0-windows7.0 is compatible. 
.NET Framework net472 is compatible.  net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.7.2

    • No dependencies.
  • .NETFramework 4.8

    • No dependencies.
  • net10.0-windows7.0

    • No dependencies.
  • net8.0-windows7.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.3 88 9/13/2026