WinUI 双引擎架构解析:Dxaml 层与 Core 层的 Peer 对象通信机制(microsoft-ui-xaml)

发布时间:2026/11/4 23:43:09

WinUI 双引擎架构解析:Dxaml 层与 Core 层的 Peer 对象通信机制(microsoft-ui-xaml) WinUI 双引擎架构解析Dxaml 层与 Core 层的 Peer 对象通信机制microsoft-ui-xaml【免费下载链接】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本文基于 dxamlvscore.md 整理并深入扩展。WinUI 代码库在架构上被清晰地切分为Dxaml 层公开、面向开发者与Core 层内部、贴近系统两大部分每个控件类型实际上由一对 Peer对等 对象组成。阅读本文后你将掌握这两层各自的职责边界、Xaml 实例的构成方式以及 Dxaml → Core 与 Core → Dxaml 两条方向上全部四种通信手段GetHandle、CoreImports/pinvokes、DxamlCore::GetPeer、DxamlServices::GetPeer与FxCallbacks并理解这些设计的历史由来与当前演进方向。背景Silverlight 留下的遗产理解 Dxaml 与 Core 的分层首先要回到 WinUI 的历史源头——Silverlight。Silverlight 是一个浏览器插件可托管在 Windows 或 Mac 上 IE、FireFox、Chrome 的网页中。最初整个 Silverlight 都是用 C 编写的位于我们今天依然称之为 core 的目录Silverlight 的 DLL 名为agcore.dll。后来在它之上增加了一个用 C# 编写的层名为System.Windows有时也被称作framework——它的设计初衷是作为 agcore 之上的一个框架层且未来可能还会有其他框架。Core 层实现了诸如DependencyObject、DependencyProperty、布局、输入、动画和渲染等基础能力。最初它只支持Canvas、TextBlock、Shapes、Animations和Storyboard这些类型。Control与Templating随后也被加入 Core但真正的控件如Button、ListBox则实现在System.Xaml中。因此形成了控件框架在 Core控件本体在System.Windows的格局随着时间推移出于性能原因部分代码又从System.Windows下沉到 Core例如Button如今就是 Core 中的CButton。原始的 Core 层通过CDependencyObject简称 CDO以 JS 对象形式暴露给浏览器因此 Core 中的一切对象都是 CDO而System.Windows类型只暴露给 .NET。例如从 JS 中能看到ItemsControl但只有 .NET 中才能看到ListBox。为了在 .NET 中访问这些类型System.Windows为每个 Core 类型都提供了 C# 包装——比如System.Windows里的Control类就是 Core 中CControl的简单包装。到了 Windows 8 时代Core 层被移植到 Windows 上System.Windows层则被用 C 重写这段重写的代码全部进入了今天的 DXaml 目录dxaml/。这套新的 C Dxaml 代码遵循了当时更现代的命名规范这正是为什么它的类没有像 Core 那样带 C 前缀——除此之外两层代码中还有很多能看出年代差异的痕迹。Xaml Core一个 Xaml 实例由两个对象构成Xaml core在这里不是指 Xaml 代码中的 Core层而是由两个对象共同组成的组合体且每个对象分别属于一个层Dxaml 层的DXamlCore对象Core 层的CCoreServices对象。两者合起来构成一个Xaml 实例。由于 WinUI 是单线程框架每个线程对应一个 Xaml 实例。这一事实是理解整个框架调度、资源访问与对象生命周期的基础所有 UI 对象都归属到所属线程的 Xaml 实例之上跨线程访问必须遵循调度Dispatcher规则。Peer 对象每个控件都是一对对象每个控件类型都由两个对象组成一个 Dxaml 层对象 一个 Core 层对象。以UIElement为例层类型可见性Dxaml 层UIElement公开面向开发者Core 层CUIElement内部Xaml 实现细节在继承关系上Dxaml 层的所有 Xaml 类型都是DependencyObjectDO的子类Core 层的所有类型都是CDependencyObjectCDO的子类更完整的对象旅程可参考 Journey of a control。这两个对象互称peer对等对象Dxaml 对象的 peer 是它的 Core 对象反之亦然。设计上有一条铁律两个 peer 不能直接对话指令流向永远是 Dxaml 层 → Core 层Core 层对象不能直接调用其 Dxaml 层 peer。这一设计源于历史Silverlight 时代 Dxaml 层当时是System.Windows与 Core 层位于不同的 DLL只是后来才合并进单一 DLLMicrosoft.UI.Xaml.dll。那为什么合并之后依然保留这一隔离因为若在 Core 层直接 include Dxaml 层的头文件会牵连引入大量头文件并可能造成循环引用。在没有良好重构策略的前提下两层之间的任何对话都通过抽象层进行。下面分别介绍两个方向上的全部通信方式。Dxaml 层到 Core 层的通信通信流向Dxaml → Core这个方向的通信相对直接主要有两种实现方式。方式一GetHandle()将公开类型强转为DependencyObject甚至UIElement然后调用GetHandle()即可拿到 Core 层的 peer 指针// 用法 // 假设 someType 是 UIElement 的子类 // 将其强转为 UIElement 后调用 GetHandle 即可拿到其 Core peer 对象 CUIElement* foo someType.CastUIElement()-GetHandle(); // 内部实现上UIElement::GetHandle 在 DependencyObject 基类层面完成操作 // 再将结果重新强转回来。以下是其定义 CUIElement* UIElement::GetHandle() const { auto result DependencyObject::GetHandle(); ASSERT(!result || result-OfTypeByIndexKnownTypeIndex::UIElement()); return static_castCUIElement*(result); }注意GetHandle()内部通过OfTypeByIndexKnownTypeIndex::UIElement()做了类型校验保证返回的 Core 对象确实是CUIElement或其派生类型随后用static_cast完成强转。方式二CoreImports.cpp即历史上的pinvokes.cpp并非所有 Dxaml 到 Core 的调用都通过GetHandle实现。在 Silverlight 时代从System.Windows调用 Core 属于托管到原生的跨越必须通过pinvoke因此存在一个pinvokes.cs文件集中存放所有对 Core 的调用。这段代码被移植到 C 后成为现在的pinvokes.cpp已改名为 CoreImports.cpp大量跨层调用都经由它完成。例如 Dxaml 层调用 Core 中的CUIElement::Arrange时就是通过CoreImports.cpp里的UIElement_Arrange方法中转。值得特别关注的是文档中的明确论断由于该边界DLL 边界已不存在这种间接层没有存在的理由应当被移除。也就是说CoreImports.cpp属于可清理的历史包袱是当前代码库中一个已知的重构方向读者在阅读或贡献代码时可留意这一点。Core 层到 Dxaml 层的通信通信流向Core → Dxaml这个方向的通信要绕一些弯子因为 Core 层不能直接引用 Dxaml 层的头文件。目前共有三种抽象手段。手段一DxamlCore::GetCurrent()与DxamlCore::GetPeer如果调用代码本身就存在于 Dxaml 层虽然它操作的是一个 Core 对象那么通过DxamlCore::GetCurrent()可以直接拿到DxamlCore实例再调用其GetPeer获取 Core 对象的 Dxaml peer。以下是来自代码库的实际片段// 代码库中的真实片段 CUIElement* publicRootVisual xamlRoot.CastXamlRoot()-GetVisualTreeNoRef()-GetPublicRootVisual(); ctl::ComPtrDependencyObject peer; DxamlCore::GetCurrent()-GetPeer(publicRootVisual, peer);这里从XamlRoot的视觉树取出公共根视觉对象publicRootVisual一个 Core 层CUIElement再借助DxamlCore::GetCurrent()-GetPeer拿到它的 Dxaml 层 peerDependencyObject并存入ComPtr以安全托管生命周期。在 Dxaml 层代码中这是获取 peer 的最直接途径。手段二DxamlServices::GetPeer如果调用代码存在于 Core 层它没有任何办法调用DxamlCore实例——因为在 Core 层 includeDxamlCore头文件需要大量重构。为此DxamlServices持有一个IDxamlCore接口DxamlCore实现该接口的实例Core 层通过调用该接口上的函数来与DxamlCore实例通信。GetPeer/TryGetPeer函数正是 Core 对象获取其 Dxaml peer 的入口。前缀Try表示允许失败失败时返回错误而非断言的版本// 定义 _Check_return_ HRESULT DxamlServices::GetPeer( _In_ CDependencyObject* pDO, _Outptr_ DependencyObject** ppObject) // 用法 CDependencyObject *foo; DirectUI::DependencyObject* DO{}; DirectUI::DxamlServices::GetPeer(foo, DO); // 返回的 DO 需强转为具体子类型 auto DxamlLayerObject static_castbarType*(DO);GetPeer()接收一个CDependencyObject*返回一个DependencyObject*之后调用方再将其强转为所需的 Dxaml 层具体类型。由于返回值可放入ComPtr可以毫不费力地享受智能指针带来的生命周期管理相关约定见 WinUI Pointers。注意_Check_return_标注要求调用方必须检查 HRESULT 返回值这是 Core 层代码的典型契约。手段三FxCallbacksFxCallbacks是又一个抽象文件用于处理某些需要从 Core 调用 Dxaml 层的常见动作位于 dxaml/xcp/dxaml/lib/FxCallbacks.cpp。与pinvokes.cpp/CoreImports.cpp类似FxCallbacks同样是 Silverlight 时代代码的移植——只不过方向相反它对应的是当年从 Core 反向调用System.Windows的那批函数即一个装满reverse pinvoke的文件。换句话说pinvokes系列管正向跨层FxCallbacks管反向跨层两者共同构成了跨层调用的双向中继站。通信机制速查表方向机制适用场景关键文件Dxaml → CoreGetHandle()直接取 Core peerUIElement/DependencyObject基类实现Dxaml → CoreCoreImports.cpp原pinvokes.cpp批量中转跨层函数调用如UIElement_Arrangedxaml/xcp/core/dll/CoreImports.cppCore → DxamlDxamlCore::GetCurrent()-GetPeer()Dxaml 层代码中为 Core 对象取 peerdxaml/xcp/dxaml/lib/DXamlCore.hCore → DxamlDxamlServices::GetPeer/TryGetPeerCore 层代码中取 Dxaml peerDxamlServices持有IDxamlCore接口实例Core → DxamlFxCallbacks常见的反向跨层动作中转dxaml/xcp/dxaml/lib/FxCallbacks.cpp总结与阅读建议Dxaml/Core 双层的 Peer 架构是 WinUI 最核心的底层设计之一它决定了对象所有权、线程模型与跨层调用约定。把握以下要点即可建立清晰心智模型一个 Xaml 实例 DXamlCoreCCoreServices每线程一份每个控件 Dxaml 对象 Core peer 对象指令只能从 Dxaml 流向 Core正向通信走GetHandle()或CoreImports.cpp其中CoreImports是文档明确标记应被移除的历史间接层反向通信通过DxamlCore::GetPeerDxaml 层代码或DxamlServices::GetPeerCore 层代码与FxCallbacks完成。如需继续深入推荐结合 Journey of a control了解 DO/CDO 的完整对象生命周期、pointers.md掌握 WinUI 的指针/引用计数约定并可直接在仓库的 dxaml/xcp/dxaml/lib/ 与 dxaml/xcp/core/ 目录中对照阅读上述源码验证每一处跨层调用的真实形态。【免费下载链接】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),仅供参考
延伸阅读

更多相关文章

2026/11/2 15:36:59

UML课程设计:学生成绩管理系统的用例图、顺序图与数据库设计

简介:学生成绩管理系统UML课程设计文档,完整呈现从可行性分析、需求规格说明到系统设计、数据库设计的全过程,可供软件工程、信息管理相关专业学生完成UML课程设计或毕业设计时参考。文档识别了管理员、教师、学生等参与者与核心用例&#xf…

2026/10/30 8:05:46

机器学习期末复习题及答案:泛化误差界、算法与评估要点

简介:《机器学习期末复习题及答案》是一份面向高校机器学习课程期末备考、需快速梳理核心考点与查漏补缺的学生,以及想集中巩固基础概念的自学者的复习资料。内容以单选题、多选题、名词解释、简答题和编程题等形式组织,覆盖数据集划分、欠拟…

2026/11/5 16:51:33

EasyU优启通PE维护盘实战指南:制作、启动与核心操作全解析

1. 为什么一个PE维护盘值得单独拿出来聊装系统、修引导、救数据、清病毒,这些活儿但凡干过几次的人都知道,真正决定效率的往往不是你手速多快,而是手边那套PE环境靠不靠谱。EasyU(圈内习惯叫优启通)就是在这个场景下被…

2026/11/5 16:26:13

Rust原来很简单二:所有权系统

Part 2 核心篇 —— 所有权系统 本篇覆盖 第 6 ~ 10 章:所有权、借用与引用、生命周期、字符串与切片、内存模型。 ⚠️ 这是全书最重要的一篇。 把它吃透,Rust 从此“很简单”;跳过它,你会处处碰壁。请慢下来,动手敲每一段代码。 第 6 章 所有权:Rust 的第一性原理 6…

2026/11/5 15:00:49

基于Hadoop+Spark的民宿智能推荐系统设计与实现

1. 项目概述:大数据时代的民宿智能推荐这个毕业设计项目融合了当前大数据领域最主流的技术栈,构建了一个完整的民宿推荐系统解决方案。作为一名长期从事大数据系统开发的工程师,我认为这个选题非常贴合实际应用场景——随着旅游业的复苏和共享…

2026/11/5 14:10:30

ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 14:10:30

UART接口24位ADC搭配RS485,解决远距离温度监控难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 14:10:30

UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑