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

为何WPF RichTextBox中TextDecorationCollection始终为空?

我查过不少同领域处理下划线逻辑的相关问题,绝大多数内容围绕添加下划线的实现展开,很少涉及下划线检测场景,现有方案普遍逻辑冗余复杂,且没有提到常规实现会出现不符合逻辑的假阴性漏判问题。另外查到的多数过往方案要么依赖TextBlock这类其他控件,要么使用的是已经过时的语法。

问题描述

在*.NET Core 3.1*环境下,需要通过编程方式检测WPF RichTextBox的选中区域是否包含任意TextDecorations格式,但调试过程中发现,哪怕选中的内容全部带有下划线,TextDecorationCollection始终返回空值。

调试时选中完全带有下划线的内联元素(Run),TextDecorationCollection返回值仍为空,对应FlowDocument的结构已确认下划线格式真实存在。

已尝试方案

  • 方案1
TextRange myrange = new TextRange(MainRtb.Selection.Start, MainRtb.Selection.End);
if (myrange.GetPropertyValue(Inline.TextDecorationsProperty).Equals(TextDecorations.Underline)) { }
  • 方案2
TextRange myrange = new TextRange(MainRtb.Selection.Start, MainRtb.Selection.End);
var obj = myrange.GetPropertyValue(Inline.TextDecorationsProperty);

if (obj == DependencyProperty.UnsetValue) {
    log.addLog("mix format");
}
if (obj is TextDecorationCollection) {
    var objProper = obj as TextDecorationCollection;

    if (objProper.Count > 0) {
        log.addLog("all underlined");
    } else {
        log.addLog("none underlined");
    }
}
  • 方案3
foreach (Block block in MainRtb.Document.Blocks) {
    Paragraph p = block as Paragraph;
    if (p != null) {
        foreach (Inline inline in p.Inlines) {
            InlineUIContainer iuic = inline as InlineUIContainer;
            if (iuic != null) {
                Console.WriteLine("found underline");
            }
        }
    }
}

问题原因

早年技术论坛有帖子提到GetPropertyValue方法存在缺陷,实际验证下来核心问题有三个:

  1. 方案1直接用Equals(TextDecorations.Underline)做判断属于引用比较,通过RTF加载、手动代码设置的下划线会生成新的TextDecorationCollection实例,哪怕集合内的装饰项完全一致,引用不同也会返回false,必然漏判。
  2. TextDecorationsProperty是集合类型依赖属性,GetPropertyValue处理这类属性时,只要选区范围内的属性值不是同一个实例,就会返回DependencyProperty.UnsetValue,哪怕所有内容都带有下划线,只要TextDecorationCollection是分别创建的,就会被判定为格式混合,直接走不到集合长度判断的分支。
  3. 方案3存在两个明显错误:一是只遍历了Paragraph下的第一层Inlines元素,遇到Span、Bold、Hyperlink这类嵌套包裹的Run元素会直接漏掉;二是错误将InlineUIContainer作为下划线判断依据,这个类型是UI元素容器,和下划线格式没有任何关联,完全无法实现检测。
    早年帖子给出的旧方案在VS2019/.NET Core 3.1环境下无法编译,会提示IEnumerable需要显式声明类型,不能直接使用。

可行实现

直接用递归遍历范围内所有文本元素的方式检测,不存在漏判问题,兼容.NET Core 3.1环境:

/// <summary>
/// 检测选中区域是否包含下划线格式
/// </summary>
private bool SelectionHasUnderline()
{
    TextRange selectionRange = new TextRange(MainRtb.Selection.Start, MainRtb.Selection.End);
    return CheckUnderlineInRange(selectionRange.Start, selectionRange.End);
}

private bool CheckUnderlineInRange(TextPointer start, TextPointer end)
{
    TextPointer current = start;
    while (current != null && current.CompareTo(end) < 0)
    {
        TextElement element = current.GetAdjacentElement(LogicalDirection.Forward) as TextElement;
        if (element != null)
        {
            // 检测内联元素的下划线
            if (element is Inline inline)
            {
                if (inline.TextDecorations != null && 
                    inline.TextDecorations.Any(td => td.Location == TextDecorationLocation.Underline))
                {
                    return true;
                }
            }
            // 检测块级元素设置的下划线
            if (element is Block block)
            {
                if (block.TextDecorations != null && 
                    block.TextDecorations.Any(td => td.Location == TextDecorationLocation.Underline))
                {
                    return true;
                }
            }
            // 递归检测嵌套容器内的元素
            if (element is Span span)
            {
                if (CheckUnderlineInRange(span.ContentStart, span.ContentEnd))
                {
                    return true;
                }
            }
            current = element.ContentEnd;
        }
        else
        {
            current = current.GetNextContextPosition(LogicalDirection.Forward);
        }
    }
    return false;
}

调用SelectionHasUnderline()即可得到正确的检测结果,不会出现全部带下划线仍返回空的假阴性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:45:38