WinUI 3 RichEditBox 数学模式实战指南:RichEditTextDocument 的 MathMode 与 MathML API 设计规范
【免费下载链接】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
本文基于 microsoft-ui-xaml 仓库中的 RichEditTextDocument-MathMode-Spec.md 编写,系统讲解 WinUI 3 中RichEditBox数学模式(Math Mode)的 API 设计、启用/禁用流程、MathML 导入导出与既有文本 API 的协同限制。读完本文,你将掌握GetMathMode、SetMathMode、GetMathML、SetMathML四个 API 的完整使用姿势、底层接口设计(ITextDocument2)以及各 API 的边界行为(错误码、内容清空规则),可直接应用于富文本公式编辑类应用开发。
背景:为什么 WinUI 3 需要数学模式
WinUI 3 的 RichEditBox 控件由RichEditTextDocument承载文本内容,应用通过GetText、SetText、Undo、Redo等 API 与文档交互。Windows SDK(UWP 侧)的RichEditTextDocument早已支持将文档模式设置为 Math,让用户以更丰富的数学表示方式输入和编辑文本,并可通过SetMathMode、SetMath、GetMath等 API 与 MathML 3.0 内容交互。
而 WinUI 3 的RichEditTextDocument此前缺少数学模式能力。为此,该 API 规范定义了在RichEditTextDocument上新增的 4 个 API:
RichEditMathMode GetMathMode()void SetMathMode(RichEditMathMode mode)void GetMathML(out String value)void SetMathML(String value)
这 4 个 API 统一编写在Microsoft.UI.Text.ITextDocument2接口中(与现有ITextDocument模式一致),并且该接口仅由RichEditTextDocument继承,保证 API 归属清晰。与 Windows SDK 相比,WinUI 3 将GetMath/SetMath提升(uplift)为GetMathML/SetMathML,明确表明其与 MathML 格式的关联;同时补上了 Windows SDK 缺失的GetMathMode读取能力,形成完整的"查询模式 + 切换模式 + 导出内容 + 导入内容"闭环。
设计决策要点(Spec Notes)
规范中明确记录了三项关键设计决策,理解它们有助于正确使用 API:
GetMathML通过 out 参数返回结果而非返回值:这是为了与同一类型上既有的RichEditTextDocument.GetTextAPI 保持风格一致。GetMathMode/SetMathMode设计为方法而非单个属性:因为切换模式会清空RichEditBox的现有内容与撤销(Undo)栈,属于带副作用的操作,不适合暴露为简单属性。- 复用现有公开枚举
Microsoft.UI.Text.RichEditMathMode:无需新增枚举类型,该枚举已包含NoMath与MathOnly两个值。
启用数学模式:SetMathMode(MathOnly)
应用在 XAML 中声明RichEditBox后,通过其TextDocument属性调用SetMathMode,传入RichEditMathMode.MathOnly即可开启数学模式:
// richEditBox 是 XAML 中添加的 RichEditBox 控件名称 richEditBox.TextDocument.SetMathMode(Microsoft.UI.Text.RichEditMathMode.MathOnly);启用后,用户可以使用 UnicodeMath 纯文本数学语法输入一个或多个方程,控件会实时将输入识别并转换为数学排版。
示例 1:用户在启用数学模式的RichEditBox中输入sin^2 x + cos^2 x = 1,^2会被求值,2 自动成为sin和cos的上标:
作为对比,未启用数学模式时RichEditBox不会对输入文本做任何数学求值,^2原样显示为普通文本:
示例 2:用户在数学模式启用状态下输入tan x = sinx/cosx,/字符被解释为除法运算符,最终呈现为sinx除以cosx的分式视觉形式(对应动图 MathMode-Example2.gif)。
从仓库实现侧看,RichEditBox在 WinUI 3 中有着完整的主题资源与默认样式支持,例如 RichEditBox_themeresources.xaml 中定义了DefaultRichEditBoxStyle,设置了Foreground、Background、FontFamily、TextWrapping、ScrollViewer滚动行为、ContextFlyout/SelectionFlyout(文本编辑命令栏)等属性;数学模式规范进一步指出,启用后内容将以Cambria Math字体呈现,这是公式排版的专用字体。
禁用数学模式:SetMathMode(NoMath)
数学模式默认是关闭的,即默认值为NoMath。应用可通过同样的 API 关闭数学模式:
// RichEditTextDocument 的 MathMode 可设为 MathOnly 或 NoMath;默认是 NoMath(未启用) richEditBox.TextDocument.SetMathMode(Microsoft.UI.Text.RichEditMathMode.NoMath);需要注意:从MathOnly切换到NoMath(或反向切换)时,RichEditBox的当前内容和 Undo 栈都会被清空,应用应在切换前做好内容保存(例如先调用GetMathML或GetText)。
导出数学内容:GetMathML
当模式为MathOnly时,应用可以用GetMathML获取RichEditBox中的数学内容,格式为 MathML 3.0:
// MathML 内容将存入 out 字符串变量 richEditBox.TextDocument.GetMathML(out String mathML);例如当RichEditBox中内容是y = x^2时(见下图),GetMathML返回如下 MathML:
<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" display="block"> <mml:mi mathcolor="#000000">y</mml:mi> <mml:mo mathcolor="#000000">=</mml:mo> <mml:msup> <mml:mrow> <mml:mi mathcolor="#000000">x</mml:mi> </mml:mrow> <mml:mrow> <mml:mn mathcolor="#000000">2</mml:mn> </mml:mrow> </mml:msup> </mml:math>可以看到 MathML 输出结构清晰:<mml:mi>表示标识符(如y、x)、<mml:mo>表示运算符(如=)、<mml:msup>表示上标结构(底数x、指数2),mathcolor属性保留文本颜色信息,display="block"表明块级展示。
边界行为:如果RichEditBox未启用数学模式(NoMath)就调用GetMathML,API 将抛出 HRESULT 错误,错误码为E_INVALIDARG。
导入数学内容:SetMathML
应用也可以在MathOnly模式下通过SetMathML以编程方式更新RichEditBox内容:
// 此示例中的 mathML 是一个 MathML 格式的字符串 richEditBox.TextDocument.SetMathML(mathML);例如,将mathML字符串初始化为以下内容:
<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" display="block"> <mml:msup> <mml:mrow> <mml:mi mathcolor="#000000">x</mml:mi> </mml:mrow> <mml:mrow> <mml:mn mathcolor="#000000">3</mml:mn> </mml:mrow> </mml:msup> <mml:mo mathcolor="#000000">+</mml:mo> <mml:mi mathcolor="#000000">y</mml:mi> <mml:mo mathcolor="#000000">></mml:mo> <mml:mn mathcolor="#000000">5</mml:mn> </mml:math>调用SetMathML后,RichEditBox内容会更新为渲染后的数学表达式(对应截图 RichEditBox-SetMathML.png)。
SetMathML的边界行为如下:
- 覆盖语义:
SetMathML会覆盖(overwrite)RichEditBox的现有内容。 - 非法输入:如果传入的
value不是格式正确的 MathML 字符串,API 返回E_INVALIDARG,且此时RichEditBox的内容会被清空。 - 未启用数学模式:在
NoMath模式下调用SetMathML会抛出 HRESULT 错误E_INVALIDARG。
数学模式下与 GetText / SetText 的协同
数学模式下,既有RichEditTextDocument.GetText和SetTextAPI 仍然可用,但选项受限:
GetText只能配合TextGetOptions.FormatRtf选项调用,返回 RTF 字符串;- 使用除
FormatRtf之外的选项调用GetText会返回E_INVALIDARG错误码; SetText可以使用现有的TextSetOptions调用。
这意味着在数学模式下,文档内容的持久化/传输链路是:数学内容以 MathML 交换(GetMathML/SetMathML),以 RTF 方式走既有文本 API(GetText/SetText)。下图演示了这一组合用法:点击按钮后,第一个RichEditBox的RichEditTextDocument以FormatRtf选项调用GetText,第二个启用数学模式的RichEditBox则以FormatRtf调用SetText,写入前一个调用返回的 RTF 内容:
API 行为速查
RichEditTextDocument 新增 API 签名
class RichEditTextDocument { // 既有 API // ... // 新增 API Microsoft.UI.Text.RichEditMathMode GetMathMode(); void SetMathMode(Microsoft.UI.Text.RichEditMathMode mode); void GetMathML(out String value); void SetMathML(String value); }各方法行为明细
| API | 用途 | 关键行为 |
|---|---|---|
GetMathMode | 返回当前模式 | 返回值只能是NoMath或MathOnly,用于查询RichEditBox当前是否处于数学模式 |
SetMathMode | 配置输入解释模式 | MathOnly启用、NoMath禁用;默认NoMath;切换模式会清空内容与 Undo 栈;数学模式下内容以 Cambria Math 字体呈现;可与GetMathML/SetMathML配合读写内容;既有GetText/SetText在数学模式下仍可用(选项受限) |
GetMathML | 以 MathML 字符串获取内容 | 仅适合MathOnly模式;未启用数学模式时抛出E_INVALIDARG |
SetMathML | 以 MathML 字符串设置内容 | 覆盖现有内容;非法 MathML 返回E_INVALIDARG并清空内容;未启用数学模式时抛出E_INVALIDARG |
API 细节:接口层设计
规范在 API Details 部分给出了完整的接口定义,从中可以看到新增能力的承载方式——既有公开枚举RichEditMathMode、新的exclusiveto(RichEditTextDocument)接口ITextDocument2,以及RichEditTextDocument对它的继承:
namespace Microsoft.UI.Text { // 既有枚举 enum RichEditMathMode { NoMath, MathOnly, }; [exclusiveto(RichEditTextDocument)] [webhosthidden] interface ITextDocument2 { Microsoft.UI.Text.RichEditMathMode GetMathMode(); void SetMathMode(Microsoft.UI.Text.RichEditMathMode mode); void GetMathML(out String value); void SetMathML(String value); }; [webhosthidden] runtimeclass RichEditTextDocument { // 既有接口 // ... // 新接口 interface Microsoft.UI.Text.ITextDocument2; }; }两点实现细节值得关注:
[exclusiveto(RichEditTextDocument)]属性确保ITextDocument2只被RichEditTextDocument这一运行时类实现,避免了接口被其他文本类型误用,与既有ITextDocument的设计保持一致;[webhosthidden]表明该接口与类型在 Web 宿主(如 WebView 承载的 XAML)中不暴露,仅面向原生/桌面 WinUI 3 应用。
仓库中的相关实现佐证
- 样式资源:RichEditBox_themeresources.xaml 定义了
RichEditBox的默认样式DefaultRichEditBoxStyle(含BasedOn="{StaticResource DefaultRichEditBoxStyle}"的隐式样式),涵盖前景/背景/边框、滚动行为、文本换行、圆角与文本编辑命令栏等设置,是数学模式内容渲染(Cambria Math 字体)之外的控件级外观基础。 - 测试与验证:测试应用
MUXControlsTestApp中保留了 RichEditBox.xml 视觉验证文件(声明了Microsoft.UI.Xaml.Controls.RichEditBox元素),说明RichEditBox属于该仓库控件测试与视觉回归验证的覆盖范围,新增数学模式 API 时可参考既有测试基础设施进行验证。
小结
WinUI 3 通过ITextDocument2接口为RichEditTextDocument补齐了数学模式能力:SetMathMode(MathOnly)一键启用、GetMathMode查询状态、GetMathML/SetMathML完成 MathML 3.0 格式的内容导入导出。实践要点可归纳为:默认NoMath;切换模式会清空内容与 Undo 栈,务必先保存;GetMathML/SetMathML仅在MathOnly模式下有效(否则E_INVALIDARG);数学模式下的既有文本 API 走 RTF 通道。以上设计与边界行为均以本仓库 API 规范文档为准,可在实现时对照验证。
【免费下载链接】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),仅供参考