Home > other >  Why is TextDecorationCollection always empty in WPF RichTextBox?
Why is TextDecorationCollection always empty in WPF RichTextBox?

Time:06-25

I've seen some questions address this problem domain and the unnecessary complexity of handling underlines (mainly applying them, but I want to detect them), but none that I can recall suggesting as I am here that the default strategies for accomplishing this create illogical false negatives. Furthermore, most of the previous questions I've referred to have used a different control (e.g. TextBlock) and/or have obselete syntax.

The problem

(.NET Core 3.1) I would simply like to programatically detect if a WPF RichTextBox selection contains any TextDecorations, but debugging shows that the TextDecorationCollection is always empty, even when the selection is all underlined.

debugging screenshot showing that TextDecorationCollection returns empty even when examining a fully underlined Inline (Run) As you can see, TextDecorationCollection returns empty even when examining a fully underlined Inline (Run)

FlowDocument format for the document in question For context, this screenshot just shows the plain text representation of the FlowDocument

What I've tried

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");
            }
        }
    }
}

Theory

This post https://social.msdn.microsoft.com/Forums/vstudio/en-US/3ac626cf-60aa-427f-80e9-794f3775a70e/how-to-tell-if-richtextbox-selection-is-underlined?forum=wpf suggests that

myrange.GetPropertyValue(Inline.TextDecorationsProperty)

doesn't work properly due to an issue inside the "GetPropertyValue()" method, but it's a very old post. I couldn't run Jim's solution exactly because he initialises an "IEnumerable" which now needs to be declared with a type of some kind - at least that's what VS2019 said.

Test Rtf File: https://docs.google.com/document/d/1YQmGsPcH4hX2XsP7KBdFqTFg4XjrSv8I/edit?usp=sharing&ouid=111968029811979231347&rtpof=true&sd=true

CodePudding user response:

Try the following method:

public static void GetDecorations(RichTextBox rtb)
{
    TextDecorationCollection decors = rtb.Selection.GetPropertyValue(Inline.TextDecorationsProperty) as TextDecorationCollection;
    if (decors == null || decors.Count == 0)
    {
        if (rtb.Selection.Start.Parent is Run run) 
        {
            if (run.Parent is Span span)
            {
                decors = span.TextDecorations;
            }
            else if (run.Parent is Paragraph para)
            {
                decors = para.TextDecorations;
            }
        }
    }

    if (decors is TextDecorationCollection tdc)
    {
        // TODO: Processing decorations...  
    }
}

I suppose the problem you are discovered is related to the particular structure of the FlowDocument after loading your RTF document and it might be described as follow.

When the RTF document is loaded for the underlined text tBox. See TextPointer for more information on text position terminology like "insertion position" a Run inline is created for this text, but the Run.TextDecorations property doesn't contain the actual decorations for this text. Instead of that the decorations settings are stored in the parent Span object that contains this Run. In another words, these decorations property is inherited from parent to child.

Therefore, if no decorations property is set on the current Run object, then you should to check the TextDecorations property in the parent object.

  • Related