在 WPF RichTextBox 中显示 HTML






4.92/5 (14投票s)
提供代码,用于在 WPF RichTextBox 或 WebBrowser 中显示可绑定的 HTML 文本。
引言
我最近需要显示一些只读文本的一部分,并对其中的一些文本进行加粗。我可以使用多个控件,但这会降低可维护性。我希望使用 HTML,因为它被很多人理解,而且似乎在其他情况下也会很有用。
RichTextBox 设计
我使用了一个行为来实现这一点,但也可以创建一个从 RichTextBox
派生的类。
public class HtmlRichTextBoxBehavior : DependencyObject
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.RegisterAttached("Text", typeof(string),
typeof(HtmlRichTextBoxBehavior), new UIPropertyMetadata(null, OnValueChanged));
public static string GetText(RichTextBox o) { return (string)o.GetValue(TextProperty); }
public static void SetText(RichTextBox o, string value) { o.SetValue(TextProperty, value); }
private static void OnValueChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
var richTextBox = (RichTextBox)dependencyObject;
var text = (e.NewValue ?? string.Empty).ToString();
var xaml = HtmlToXamlConverter.ConvertHtmlToXaml(text, true);
var flowDocument = XamlReader.Parse(xaml) as FlowDocument;
HyperlinksSubscriptions(flowDocument);
richTextBox.Document = flowDocument;
}
private static void HyperlinksSubscriptions(FlowDocument flowDocument)
{
if (flowDocument == null) return;
GetVisualChildren(flowDocument).OfType<Hyperlink>().ToList()
.ForEach(i => i.RequestNavigate += HyperlinkNavigate);
}
private static IEnumerable<DependencyObject> GetVisualChildren(DependencyObject root)
{
foreach (var child in LogicalTreeHelper.GetChildren(root).OfType<DependencyObject>())
{
yield return child;
foreach (var descendants in GetVisualChildren(child)) yield return descendants;
}
}
private static void HyperlinkNavigate(object sender,
System.Windows.Navigation.RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
}
这段代码依赖于 Microsoft 提供的代码;HtmlToXamlConverter
。所有这些 Microsoft 代码都包含在示例项目中的 HtmlConverter 文件夹中。
将 Behavior 与 RichTextBox 一起使用
使用行为的最直接方法如下
<RichTextBox Grid.Row="1"
local:HtmlRichTextBoxBehavior.Text="{Binding Text}" />
您可能会遇到一些意想不到的问题,因为仍然可以编辑 RichTextBox
。 还有一些其他问题。 为了解决至少大多数这些问题,我做了以下操作
<RichTextBox Background="Transparent"
BorderThickness="0"
behaviors:RichTextBoxHelper.Text="{Binding Name}"
IsDocumentEnabled="True"
IsReadOnly="True" />
这使得 RichTextBox
看起来更像一个 TextBox
。 IsDocumentEnabled="True"
是启用超链接所必需的。 IsReadOnly="True"
确保内容无法更改。
WebBrowser 设计
也使用了一个行为来绑定包含 HTML 的 string
到 WebBrowser
的内容
public class WebBrowserBehavior
{
public static readonly DependencyProperty BodyProperty =
DependencyProperty.RegisterAttached("Body", typeof(string), typeof(WebBrowserBehavior),
new PropertyMetadata(OnChanged));
public static string GetBody(DependencyObject dependencyObject)
{
return (string)dependencyObject.GetValue(BodyProperty);
}
public static void SetBody(DependencyObject dependencyObject, string body)
{
dependencyObject.SetValue(BodyProperty, body);
}
private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
((WebBrowser)d).NavigateToString((string)e.NewValue);
}
这是一种尽可能简单的行为
将 Behavior 与 WebBrowser 一起使用
使用行为的最直接方法如下
<WebBrowser local:WebBrowserBehavior.Body="{Binding Text}" />
关注点
目前,超链接在 RichTextBox
中不起作用。 显然这是 WPF RichTextBox
的一个问题。 如果对 WinForm RichTextBox
执行类似操作,则 "DetectUrls="True"
" 将启用超链接。
当在 WebBrowser
控件中单击超链接时,URI 会立即打开。 这可能不是特别理想的,因此可能需要禁用它。
使用 RichTextBox
的一个优点是,该行为可以更新为进行反向转换。 实际上,一些关键组合键在 RichTextBox
中有效,因此可以使用 "ctrl + b" 组合键加粗条目。 我没有创建反向转换的能力,但那将是一项简单的任务。
历史
- 2016/02/05:初始版本。
- 2016/03/05:将
WebBrowser
版本添加到示例