首页
/ PowerToys Settings V2 项目架构总览:WinUI3、MVVM 与 Runner 通信的三层设计

PowerToys Settings V2 项目架构总览:WinUI3、MVVM 与 Runner 通信的三层设计

2026-09-05 18:34:49作者:明树来

PowerToys 的设置界面(Settings V2)是一个基于 Windows App SDK 的 WinUI3 非打包(Unpackaged).NET 桌面应用。本文基于仓库中 项目总览文档 展开,逐层解析 Settings 工程的三部分构成——UI 组件层、视图模型/数据层、以及与主进程 Runner 的通信职责,并结合 src/settings-ui/ 下的实际工程文件,说明 MVVM 分层在 PowerToys 中的落点、快捷键(Hotkey)逻辑所在位置,以及设置应用被 Runner 拉起和终止的完整生命周期。

Settings V2 的 UI 架构图

一、Settings V2 是什么:Windows App SDK + WinUI3 Unpackaged 应用

原总览文档对 Settings 的定义是一句话:Settings is Windows App Sdk WinUI3 .Net Unpackaged desktop application。这句话里包含三个关键技术选型,均可在工程文件中得到印证:

选型 含义 仓库证据
Windows App SDK 使用微软面向 WinUI3 的跨打包/非打包开发 SDK,而非传统的 UWP/Win32 框架 PowerToys.Settings.csproj 中引用 Microsoft.WindowsAppSDK
WinUI3 UI 用 XAML + WinUI 控件描述,C# 编写视图模型 同上,csproj<UseWinUI>true</UseWinUI>
.Net Unpackaged .NET 桌面应用形态,不使用 MSIX 打包,以散文件方式随 PowerToys 安装目录分发 csproj<WindowsPackageType>None</WindowsPackageType>

此外,csproj<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained> 表明运行时随应用自带(self-contained),配合 <OutputPath>$(RepoRoot)$(Platform)\$(Configuration)\WinUI3Apps</OutputPath> 可以看到,Settings 的构建产物统一输出到解决方案输出目录下的 WinUI3Apps 子目录,由安装器(installer/ 下的 Settings.wxs)与 PowerToys 主体一起打包分发。

从依赖列表还能看到两个对理解架构很重要的引用(csproj):

  • StreamJsonRpc:用于进程间 RPC 通信的 NuGet 包,是 Settings 与 Runner 之间 IPC 的基础设施;
  • CommunityToolkit.WinUI.* 系列:WinUI3 社区工具包,提供设置页常用控件(如 SettingsExpander、Segmented 等)。

二、工程结构总览:三部分构成与 MVVM 分层

总览文档 的核心内容是 Settings V2 的工程结构。文档指出该工程遵循 MVVM 架构模式(图形界面与视图模型分离),并将工程划分为三个部分:

src/settings-ui/
├── Settings.UI/            # ① UI 组件(Views/XAML)+ ③ Settings Runner 进程宿主
│   ├── SettingsXAML/       #    页面、控件、OOBE 引导窗口
│   └── ViewModels/         #    ShellViewModel 与各模块 ViewModel
├── Settings.UI.Library/    # ② 数据模型/视图模型数据(XSettings、XProperties)
├── Settings.UI.Controls/   # 公共 UI 控件库
├── Settings.UI.UnitTests/  # 单元测试
└── Settings.UITests/       # UI 自动化测试

下面按文档的三个小节逐一展开,并补充源码层面的细节。

2.1 UI 组件:src/settings-ui/Settings.UI/

文档原文:"The UI Components are part of PowerToys.Settings project. It contains the xaml files for each of the UI components. It also contains the Hotkey logic for the settings control."

即 UI 组件属于 PowerToys.Settings 工程,包含各 UI 组件的 XAML 文件,同时包含设置界面中快捷键(Hotkey)控制相关的逻辑

从源码结构看,这一描述对应如下布局:

2.2 视图模型数据:src/settings-ui/Settings.UI.Library

文档原文:"The Settings.UI.Library project contains the data that is to be rendered by the UI components."

即 Library 工程存放"供 UI 组件渲染的数据"。它是纯 C# 类库,是 MVVM 中 Model 与 ViewModel 绑定的数据契约层。从 目录内容 看,其组织规律非常清晰,每个模块都有成对的数据模型:

  • XxxSettings.cs:模块的运行时状态(开关、参数值),例如 AdvancedPasteSettings.csAwakeSettings.csColorPickerSettings.cs
  • XxxProperties.cs:模块的静态属性描述(模块名、启用开关元数据等),例如 AwakeProperties.csCmdPalProperties.cs
  • 基础类型:BasePTModuleSettings 是所有模块设置的基类,BoolProperty.csDoubleProperty.cs 等则是带默认值与序列化/反序列化能力的属性封装,供 ViewModel 与配置文件之间做双向同步。

这种"Settings(状态)+ Properties(元数据)"的成对设计,使得 UI 层无需关心 JSON 配置文件格式,只需绑定 Library 暴露出的强类型属性即可。

2.3 Settings Runner:界面变更到 Runner 的通信中枢

文档原文:"The function of the settings runner project is to communicate all changes that the user makes in the user interface, to the runner so that it can be dispatched and reflected in all the modules."

注意这里"settings runner"指的是设置进程本身承担的职责:把用户在界面做的每一次变更,通信给 PowerToys 主进程(Runner,位于 src/runner/),由 Runner 统一分发给各个 PowerToy 模块并生效。

这个进程的生命周期在 App.xaml.cs 中体现得最完整:

  1. 由 Runner 带参拉起。设置进程启动时接收 Runner 传入的一组命令行参数,参数枚举 定义了全部 10 个位置参数:

    参数 含义
    PTPipeName / SettingsPipeName 与 Runner 双向通信的两个命名管道名
    PTPid Runner 进程 PID(存入 App.PowerToysPID
    Theme 主题(旧版设置的遗留参数)
    ElevatedStatus / IsUserAdmin 是否以管理员身份运行 / 用户是否为管理员(影响部分模块可用性显示)
    ShowOobeWindow / ShowScoobeWindow 是否显示 OOBE(首次配置)/ SCOBE(升级后引导)窗口
    ContainsSettingsWindow 是否打开设置主窗口
  2. 建立 IPC 并注册回调。构造函数中初始化 TwoWayPipeMessageIPCManaged(来自 PowerToys.Interop,对应 src/interop/ 工程),Runner 侧发来的消息通过 IPCMessageReceivedCallback 回调注入 UI。

  3. 等待 Runner 的终止信号。构造函数尾部调用 NativeEventWaiter.WaitForEventLoop(Constants.PowerToysRunnerTerminateSettingsEvent(), ...)App.xaml.cs):设置进程挂起等待一个 Windows 命名事件,当主 Runner 释放该事件时,设置进程清理 ETW Trace 后以退出码 0 结束。也就是说,设置进程的生命周期完全受 Runner 管控——Runner 退出或需要重载设置时,通过事件触发设置进程优雅退出。

  4. 变更下发。用户修改任何开关或参数后,对应模块的 ViewModel 经 IPCResponseService 将 JSON 形式的设置变更发送到 Runner 管道;Runner 读取后更新 powertoys_settings.json 并通知各模块。这条链路的更细粒度文档见 Runner IPC 文档模块通信文档

三、MVVM 在 Settings V2 中的落点

总览文档 明确指出工程遵循 MVVM(Model-View-ViewModel)模式,图形界面与视图模型分离。结合前面的源码结构,可以把三层对应关系归纳为:

MVVM 角色 代码位置 说明
View(视图) src/settings-ui/Settings.UI/SettingsXAML/ XAML 页面 + 控件代码,只负责呈现与用户输入
ViewModel src/settings-ui/Settings.UI/ViewModels/ ShellViewModel 管理导航/页面生命周期;各 XxxViewModel 暴露绑定属性与命令
Model(数据) src/settings-ui/Settings.UI.Library/ XxxSettings / XxxProperties 强类型数据模型,含序列化契约
跨进程服务 src/settings-ui/Settings.UI/Services/ IPCResponseService 等,把 ViewModel 的变更序列化后经管道交给 Runner

ShellViewModel 作为导航壳(实现见)持有当前页面集合与导航状态,每个模块页面都继承 PageViewModelBase,保证"返回"导航、页面标题、模块状态图标等行为一致。其可测性由 Settings.UI.UnitTests 中的单元测试覆盖(例如 ShellViewModelTests),这从侧面印证了 View 与 ViewModel 确实解耦——测试无需启动 XAML 即可验证导航逻辑。

四、进一步深入:配套文档地图

总览文档 是 Settings 系列文档的入口(见 系列索引)。读懂本篇后,可按主题继续阅读同目录下的细化文档:

五、小结

PowerToys Settings V2 的本质是一个"受 Runner 管控生命周期的 WinUI3 非打包应用":

  1. 技术栈:Windows App SDK + WinUI3 + .NET Unpackaged,self-contained 运行时随安装目录分发;
  2. 分层Settings.UI(XAML 视图 + ViewModel + Hotkey 逻辑)与 Settings.UI.Library(Settings/Properties 数据模型)分离,严格执行 MVVM;
  3. 通信:进程由 Runner 带 10 个参数拉起,通过 StreamJsonRpc 命名管道双向通信,所有界面变更经 IPCResponseService 下发至 Runner,再分发给各 PowerToy 模块;进程退出则由 Runner 的命名事件触发,优雅收尾。

理解这套结构后,无论是排查"设置改不动"、"快捷键冲突提示异常",还是为某个 PowerToy 模块新增设置页,都能快速定位到对应的 ViewModel、数据模型与 IPC 服务文件。

登录后查看全文
热门项目推荐
相关项目推荐