拓冰建站拓冰建站
首页 / 资讯中心 / 正文

WinUI 3 自定义 MRT ResourceManager:通过 Application.ResourceManagerRequested 事件接管资源解析

WinUI 3 自定义 MRT ResourceManager通过 Application.ResourceManagerRequested 事件接管资源解析【免费下载链接】microsoft-ui-xamlWinUI: a modern UI framework with a rich set of controls and styles to build dynamic and high-performing Windows applications.项目地址: https://gitcode.com/GitHub_Trending/mi/microsoft-ui-xaml导读本文基于 WinUImicrosoft-ui-xaml仓库中的设计文档 custom-mrt-resourcemanager.md系统讲解 WinUI 3 如何通过新增的Application.ResourceManagerRequested事件让应用在 XAML 框架懒加载构造ResourceManager之前注入自定义的IResourceManager实现从而在底层使用 System MRT而非默认的 MRT Core解析资源。读完本文你将理解该 API 的设计动机、事件参数与完整实现逻辑、正确的订阅时机与线程语义以及为什么事件形式优于属性或虚方法回调等替代方案并能在自己的 WinUI 3 应用尤其是像文件资源管理器那样依赖 System MRT 能力的 Shell 类应用中落地这一能力。背景为什么 File Explorer 需要 System MRTWinUI 3 默认使用MRT CoreMicrosoft.Windows.ApplicationModel.Resources作为资源管理系统。MRT Core 面向绝大多数普通应用是足够的但它存在一个关键能力缺口无法解析位于主资源映射main resource map兄弟位置的资源siblings of the main resource map。而文件资源管理器File Explorer以及整个 Shell 的资源管理场景恰好强依赖这种能力因此它们必须使用System MRT而非 MRT Core。System MRT 与 MRT Core 是两套 API 面如果直接让应用切换到底层实现会破坏现有 MRT Core 消费者的兼容性。为解决这一矛盾操作系统层面新增了一个MRT Core 与 System MRT 之间的翻译层translation layer shim它在内部使用 System MRT 完成实际的资源解析同时对外呈现与 MRT Core 完全兼容的 API 表面。这样普通应用代码无需改动而需要 System MRT 能力的应用则可以通过翻译层获得能力。但要让这套机制真正生效WinUI 3 必须改为消费这个翻译层 shim而不是自行创建自己的 MRT CoreResourceManager—— 这正是本文所述 API 要解决的问题。API 设计新增到 Application 类的事件设计文档提出在Application类上新增一个事件ResourceManagerRequested。该事件会在 XAML 核心懒加载构造ResourceManager实例以解析资源 URI 之前被触发参见 ModernResourceProvider.cpp从而让 WinUI 有机会向应用索要一个自定义的IResourceManager实现并用它替换标准的 MRT CoreResourceManager。新 API 的完整形态如下C/WinRT 风格的runtimeclass定义runtimeclass ResourceManagerRequestedEventArgs { Microsoft.Windows.ApplicationModel.Resources.IResourceManager CustomResourceManager; }; unsealed runtimeclass Application { // pre-existing API // ... event Windows.Foundation.TypedEventHandlerObject,Microsoft.UI.Xaml.ResourceManagerRequestedEventArgs ResourceManagerRequested; };要点拆解ResourceManagerRequestedEventArgs是一个新的事件参数类型包含一个可写属性CustomResourceManager类型为Microsoft.Windows.ApplicationModel.Resources.IResourceManager即 MRT Core 的接口。事件签名采用标准的TypedEventHandlerObject, ResourceManagerRequestedEventArgssender为Object实际是触发事件的Application实例。Application声明为unsealed runtimeclass表示该事件对普通应用同样可用且不要求应用必须派生自Application。实现逻辑伪代码与源码级佐证设计文档给出了该 API 背后的实现逻辑非常直观raise event with eventargs args if args.CustomResourceManager ! null then resourceManager args.CustomResourceManager else resourceManager new Microsoft.Windows.ApplicationModel.Resources.ResourceManager()即触发事件 → 若事件参数中应用已填充自定义ResourceManager则使用之否则回退到默认的 MRT CoreResourceManager。这一设计在实际源码中得到了印证。在 ModernResourceProvider.cpp 的ModernResourceProvider::Create中框架先通过回调FxCallbacks::FrameworkApplication_GetResourceManagerOverrideFromApp向应用层询问是否有自定义ResourceManager只有在该调用失败或返回空时才ActivateInstance创建默认实例// Give the app a chance to provide its own ResourceManager to handle app resources HRESULT xr FxCallbacks::FrameworkApplication_GetResourceManagerOverrideFromApp(resourceProvider-m_appResourceManager); if (FAILED(xr) || resourceProvider-m_appResourceManager nullptr) { IFC_RETURN(wf::ActivateInstance( wrl_wrappers::HStringReference(RuntimeClass_Microsoft_Windows_ApplicationModel_Resources_ResourceManager).Get(), (resourceProvider-m_appResourceManager))); }从类成员定义见 ModernResourceProvider.h可以看到ModernResourceProvider内部维护了两套资源管理上下文m_appResourceManager/m_appResourceContext用于加载应用自身的resources.pri这也是事件注入自定义IResourceManager所覆盖的对象m_frameworkPackageResourceManager/m_frameworkPackageResourceContext用于加载WinUI framework package 的resources.pri通过ProbeForFrameworkPackageResourcesPri探测路径后由IResourceManagerFactory::CreateInstance创建。无论使用默认还是自定义的ResourceManager随后InitializeContext()都会在其上创建对应的ResourceContext并同步一系列资源限定符qualifierContrast对比度/高对比度主题、DeviceFamily设备族、HomeRegion家庭区域、Language语言与布局方向、Scale缩放比例、Theme主题相关实现分布在UpdateContrastQualifier、UpdateDeviceFamilyQualifier、UpdateHomeRegionQualifier、UpdateLanguageAndLayoutDirectionQualifiers、UpdateScaleQualifier、UpdateThemeQualifier等函数中。这意味着自定义ResourceManager必须能正常配合这些限定符的读写get_QualifierValues/Insert工作框架的后续资源解析流程才会按预期执行。使用方式订阅时机与线程语义设计文档对应用侧的使用给出了两条明确指引1. 在Application构造函数中订阅事件。因为 WinUI 在初始化早期框架自动加载App.xaml时就需要一个ResourceManager所以事件订阅必须放在应用自定义Application对象的构造函数中完成。应用只需注册Application.ResourceManagerRequested的事件处理程序并在处理程序中向传入的事件参数对象的CustomResourceManager属性填入自己的IResourceManager实现即可。由于订阅与填充都发生在事件被触发即 XAML 核心懒加载构造ResourceManager之前框架便能在第一步创建时直接拿到应用提供的实现。// 伪代码示意在 App 构造函数中订阅 public App() { this.ResourceManagerRequested OnResourceManagerRequested; } private void OnResourceManagerRequested(object sender, ResourceManagerRequestedEventArgs args) { args.CustomResourceManager new MyCustomResourceManager(); }2. 线程语义每个线程返回各自的IResourceManager实例。虽然并不强制要求IResourceManager实例不得跨线程共享但为了与 WinUI 的默认语义保持一致每个收到Application.ResourceManagerRequested事件的线程都应返回它自己创建的IResourceManager实例。这提示实现者事件处理逻辑需要感知线程上下文为不同线程创建独立的资源管理器避免将某个线程的上下文状态泄漏到其他线程。设计决策为什么定义在 Application 上将新事件声明在Application类上是经过权衡的刻意选择设计文档给出了两个核心理由Application是应用级 API 与服务的汇聚点其他 app-wide 的 API 和服务例如DebugSettings、Application.Resources、IXMP 实现等都定义在Application上资源管理器同样属于应用级基础设施放这里语义一致、便于发现。Application.Current实例在启动早期即可用框架初始化App.xaml时就存在Application实例这保证了事件能在框架需要ResourceManager的第一时间被订阅和触发不存在错过窗口期的问题。同时设计文档也前瞻性地指出未来有计划让应用通过 XAML islands 使用 WinUI 而无需经过Application类一旦该特性设计完成这个事件应被考虑迁移到新的模式上。也就是说当前把事件放在Application上是与现有生命周期模型最匹配的选择但并非永久绑定的最终形态。替代方案对比为什么不用属性或虚方法设计文档评估了两种替代方案并解释了其缺陷这对理解该 API 的形态很有价值方案一一个由应用填充其 ResourceManager 的属性设想在框架上暴露一个属性让应用把自己的ResourceManager塞进去。其致命缺点在于向框架提供ResourceManager的时间窗口不是 API 显式承诺的一部分。虽然原则上框架可以拒绝应用过晚的赋值行为但允许应用做一件注定会被拒绝的事本身就是糟糕的 API 设计——不如从一开始就不允许这种动作发生。事件机制天然将提供时机锚定在框架需要资源管理器的确切时刻从 API 层面杜绝了时序错误。方案二应用可重写的虚回调方法从技术上看虚方法回调与订阅事件非常相似但它**把开发者锁定在必须自定义一个派生自Application的类**这一模式上。而 WinUI 的新代码正在刻意摆脱这种派生Application才能定制行为的模式这也是Application保持unsealed但事件成为首选机制的原因之一。事件订阅允许任意对象注册处理程序无需改变应用类的继承结构对现有和未来应用形态都更友好。总结Application.ResourceManagerRequested事件为 WinUI 3 打开了一条通往 System MRT 的官方通道能力层面它让依赖主资源映射兄弟资源等高级能力的 Shell 类应用File Explorer 是首个也是主要的用户能够无缝接入 System MRT同时保持 MRT Core API 表面兼容机制层面事件在 XAML 核心懒加载构造ResourceManager之前触发应用在构造函数中订阅并填充CustomResourceManager即可完成替换未填充时框架自动回退到默认 MRT CoreResourceManager普通应用零改动实现层面ModernResourceProvider实现 / 头文件负责将该自定义管理器接入应用resources.pri的加载流程并同步维护语言、缩放、主题等资源限定符。如果你正在开发需要超越 MRT Core 能力边界、且无法直接迁移到 System MRT 的 WinUI 3 应用这个事件就是官方设计推荐的接入点同时请留意其未来可能随 XAML islands 模式演进而迁移的规划。【免费下载链接】microsoft-ui-xamlWinUI: a modern UI framework with a rich set of controls and styles to build dynamic and high-performing Windows applications.项目地址: https://gitcode.com/GitHub_Trending/mi/microsoft-ui-xaml创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门