TextBlock 中的基本 HTML 标记






4.73/5 (6投票s)
为 WPF TextBlock 区域提供基本 HTML 标记支持
引言
好吧,让我们看看。我最近开始学习大量的新语言,看看我能多快学会它们,并且鉴于我由于学业而拥有的巨大空闲时间,进展非常顺利。无论如何,大约两周前我决定开始学习 WPF,因为微软似乎越来越远离 Window Forms,我以前最喜欢的 UI 设计框架。
我当时忙于编写一些代码,这些代码应该在弹出窗口中向用户显示插件的状态,并且发现由于某些模糊的原因,WPF 的 TextBlock
控件不支持任何类型的内联标记,而无需经历大量的循环。我不愿意让任何希望为我的应用程序开发插件的人的生活变得困难,所以我决定编写一个快速解析器,将基本的 HTML 标记转换为 WPF 可以使用的形式。几分钟后,我就有了这个,它运行得很好,并满足了我所有的要求,所以我认为它可能对将来有需要的人有用。
背景
WPF 格式化文档的总体思路是基于面向对象的方法。虽然这起初可能看起来有点奇怪,但原因很简单,如果你围绕对象设计整个文档系统,那么添加内联控件非常容易。这是 Window Forms 上的 RichTextBox
在没有花费大量痛苦工作的情况下无法做到的。
这种方法的明显缺点与其优点相同。也就是说,所有文本也都是以对象的形式存在。虽然 TextBlock
控件确实提供了一个 Text 属性,可以用来将控件中的文本设置为字符串的内容,但这不允许你指定一些可以通过 XAML 指定的漂亮的标记。当动态分配文本时,这尤其成为一个问题。
解决方案是声明对象来表示标记,并将它们添加到 TextBlock
上提供的 Inlines
集合中。这通常以以下方式完成
textBlock.Inlines.Add(new Bold(new Run("Show me some text!")));
但是,如果你想使用 Text
属性添加一些粗体文本,如下所示
textBlock.Text = "<Bold>Show me some text!</Bold>";
你会很快意识到它不起作用。在你看着我说“当然不是,<Bold> 不是粗体样式的 HTML 代码”之前,请记住 WPF 使用他们自己的解析器,并且在 XAML 中 <Bold> 是正确的用法。
我的解决方案是编写一些代码,它可以解析标记标签,然后自动生成可以添加的新内联对象。这听起来比实际情况简单得多,因为要做到这一点,你需要动态生成具有不同类型的对象。值得庆幸的是,C# 有一个称为反射的功能,允许你从程序集、类型和许多其他来源创建对象,而无需拥有它们的代码,也无需在设计时知道它们的类型。
介绍就到此为止,现在开始介绍代码的基本概述以及如何使用它。
使用代码
代码真的很容易使用,只需将其添加到你现有的项目中,然后执行以下操作
textBlock.Inlines.AddRange(SierraLib.UI.WPF.Text.MarkupProcessor.HTMLtoWPF("<b><u><i>Show me some text!</i></u></b>"));
至于它是如何做到这一点的,那就有点复杂了。源代码都有很好的文档记录,因此你可以阅读这些文档以更好地了解幕后发生的事情,但基本思路是这样的
Regex 对象用于查找和返回匹配项的列表。这些匹配项可以是标记标签或文本。如果它是一个标记标签并且不是一个结束标签,那么我们将该标记元素的相应类型添加到一个堆栈中,然后该堆栈用于稍后应用样式。一旦解析器找到一个文本元素,我们就开始应用样式。这是通过首先检查是否需要应用任何样式来完成的,如果没有,我们只是添加文本,但如果有样式,我们首先创建将要添加的项目,首先创建其最深层的子元素,然后向后工作,每次用一个新元素替换最后一个子元素,该元素的子元素是最后一个子元素。这导致我们拥有与 WPF 中的标准标记声明等效的东西。
最后,当所有元素都已创建时,我们返回一个包含所有标记元素的列表,应添加这些标记元素以创建用户正在寻找的效果。
关注点
对于任何不熟悉正则表达式或反射的人,我建议阅读它们。它们是非常有用的知识,当你开始编写更复杂的程序时,你会发现自己经常使用它们。此外,没有什么比 (?<this>[cC][oO]{2}[lL]!?) 更酷的了。好吧,正则表达式除外
已知问题
- 标记不会扩展到第一个结束标签或换行符 (<br/>) 之外
历史
版本 1.0
初始发布