You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中能否将TextRange的Inline属性保存至RTF格式?

仿Word项目RTF存储问题

项目流程

  • 从数据库获取nvarchar(max)类型的RTF内容
  • 加载RichTextBox时转换RTF:
using (var stream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(rtfString)))
{
    TargetRichTextBox.Selection.Load(stream, DataFormats.Rtf);
}
  • 编辑后将内容保存回数据库:
public string ConvertRichTextBoxToRtf(RichTextBox richTextBox)
{
    if (richTextBox == null) throw new ArgumentNullException(nameof(richTextBox));

    using (var memoryStream = new System.IO.MemoryStream())
    {
        var range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
        range.Save(memoryStream, DataFormats.Rtf);
        return System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
    }
}

问题描述

通过TextRange.ApplyPropertyValue(Inline.propName, value)设置的所有属性在运行时有效,但无法保存到RTF字符串中;而TextRange.ApplyPropertyValue(TextElement.propName, value)设置的属性则能正常保存。

疑问:

  • 是否需要改用XML或XAML存储内容?
  • MemoryStream格式是否有误?
  • 还是Inline属性的用法不正确?

设置Inline属性的示例代码:

public void SetSelectionToSubscript(TextRange range)
{
    if (range.IsEmpty) return; // 不为空选区应用格式

    object currentBaseline = range.GetPropertyValue(Inline.BaselineAlignmentProperty);

    if (currentBaseline is BaselineAlignment alignment && alignment == BaselineAlignment.Subscript)
    {
        // 重置为普通文本
        range.ApplyPropertyValue(Inline.BaselineAlignmentProperty, BaselineAlignment.Baseline);
        range.ApplyPropertyValue(TextElement.FontSizeProperty, MyFondSize); // 重置字体大小
    }
    else
    {
        // 应用下标格式
        range.ApplyPropertyValue(Inline.BaselineAlignmentProperty, BaselineAlignment.Subscript);
        range.ApplyPropertyValue(TextElement.FontSizeProperty, MyFondSize - 2); // 调整字体大小实现下标效果
    }
}

问题原因与解决方案

原因分析

问题核心是RTF格式的兼容性限制:

  • RTF是通用文本格式标准,仅支持有限的文本属性标记。WPF的Inline类下部分属性(比如BaselineAlignmentProperty)属于WPF特有的UI属性,RTF标准中没有对应映射,因此RichTextBox导出RTF时会忽略这些属性。
  • TextElement的多数属性(如FontSizeProperty)是RTF原生支持的格式,所以能正常保存到RTF字符串。
  • 你的MemoryStream用法完全正确,编码和流处理没有问题。

解决方案

方案1:继续用RTF存储,改用RTF支持的属性

如果必须保留RTF存储,替换WPF特有的Inline属性为RTF可识别的标准属性。以下标为例,改用Typography.VariantsProperty,该属性可被RTF导出正确识别:

public void SetSelectionToSubscript(TextRange range)
{
    if (range.IsEmpty) return;

    object currentVariant = range.GetPropertyValue(Typography.VariantsProperty);

    if (currentVariant is FontVariants variant && variant == FontVariants.Subscript)
    {
        range.ApplyPropertyValue(Typography.VariantsProperty, FontVariants.Normal);
        range.ApplyPropertyValue(TextElement.FontSizeProperty, MyFondSize);
    }
    else
    {
        range.ApplyPropertyValue(Typography.VariantsProperty, FontVariants.Subscript);
        range.ApplyPropertyValue(TextElement.FontSizeProperty, MyFondSize - 2);
    }
}

方案2:改用XAML格式存储

如果需要完整保留所有WPF文本属性(包括自定义Inline属性),推荐改用XAML存储FlowDocument完整内容:

  • 保存时将FlowDocument序列化为XAML字符串:
public string ConvertRichTextBoxToXaml(RichTextBox richTextBox)
{
    if (richTextBox == null) throw new ArgumentNullException(nameof(richTextBox));
    return System.Windows.Markup.XamlWriter.Save(richTextBox.Document);
}
  • 加载时将XAML字符串反序列化为FlowDocument:
public void LoadRichTextBoxFromXaml(RichTextBox richTextBox, string xamlString)
{
    if (richTextBox == null) throw new ArgumentNullException(nameof(richTextBox));
    using (var stringReader = new System.IO.StringReader(xamlString))
    using (var xmlReader = System.Xml.XmlReader.Create(stringReader))
    {
        richTextBox.Document = (FlowDocument)System.Windows.Markup.XamlReader.Load(xmlReader);
    }
}

这种方式可100%保留所有WPF文本元素属性,无兼容性问题,但存储内容为XAML格式,无法直接用其他RTF编辑器打开。

内容的提问来源于stack exchange,提问作者Korosevar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:30:03