question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Paragraph.InsertAfter Invalid Operation Error in Textbox

See original GitHub issue

Receiving an invalid operation error when calling Paragraph.InsertAfter when the paragraph is in a floating object/textbox. Please note the function below that I found on stack overflow. To reproduce this issue use a document that has a picturebox/textbox with word or phrase you are wanting to highlight. It blows up on the line paragraph.InsertAfter(highlightRun, found.Run);

  • .NET Target: 4.6.1
  • DocumentFormat.OpenXml Version: 2.9.1
        static void HighLightText(Paragraph paragraph, string text)
        {
            // Search for a first occurrence of the text in the text runs
            var found = paragraph
                .Descendants<Run>()
                .Where(r => !string.IsNullOrEmpty(r.InnerText) && r.InnerText != "\\s" && r.GetFirstChild<Text>() != null)
                .Select(r =>
                {
                    var runText = r.GetFirstChild<Text>();
                    int index = runText.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase);

            // 'Run' is a reference to the text run we found,
            // TextNode is a reference to the run's Text object,
            // 'TokenIndex` is the index of the search string in run's text
            return new { Run = r, TextNode = runText, TokenIndex = index };
                })
                .FirstOrDefault(o => o.TokenIndex >= 0);

            // Nothing found -- escape
            if (found == null || found.Run == null)
            {
                return;
            }

            // Create a node for highlighted text as a clone (to preserve formatting etc)
            var highlightRun = found.Run.CloneNode(true);

            // Add the highlight node after the found text run and set up the highlighting
            paragraph.InsertAfter(highlightRun, found.Run);
            highlightRun.GetFirstChild<Text>().Text = text;
            RunProperties runPro = new RunProperties();
            Highlight highlight = new Highlight { Val = HighlightColorValues.Yellow };
            Vanish vv = new Vanish();

            runPro.AppendChild(highlight);
            runPro.AppendChild(vv);
            highlightRun.InsertAt(runPro, 0);

            // Check if there's some text in the text run *after* the found text
            int remainderLength = found.TextNode.Text.Length - found.TokenIndex - text.Length;
            if (remainderLength > 0)
            {
                // There is some text after the highlighted section --
                // insert it in a separate text run after the highlighted text run
                var remainderRun = found.Run.CloneNode(true);
                paragraph.InsertAfter(remainderRun, highlightRun);
                var textNode = remainderRun.GetFirstChild<Text>();
                textNode.Text = found.TextNode.Text.Substring(found.TokenIndex + text.Length);

                // We need to set up this to preserve the spaces between text runs
                textNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
            }

            // Check if there's some text *before* the found text
            if (found.TokenIndex > 0)
            {
                // Something is left before the highlighted text,
                // so make the original text run contain only that portion
                found.TextNode.Text = found.TextNode.Text.Remove(found.TokenIndex);

                // We need to set up this to preserve the spaces between text runs
                found.TextNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
            }
            else
            {
                // There's nothing before the highlighted text -- remove the unneeded text run
                paragraph.RemoveChild(found.Run);
            }
        }

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
twsouthwickcommented, Mar 28, 2019

The issue is that found.Run is not a child of paragraph. The documentation isn’t really helpful here and the exception wasn’t being populated with a message. I’ve supplied a PR for this.

To fix your code, you’ll need to insert/remove to/from the parent. So, instead of

paragraph.InsertAfter(highlightRun, found.Run);

do

found.Run.Parent.InsertAfter(highlightRun, found.Run);

You’ll also have an issue with paragraph.RemoveChild(found.Run), which you can replace with found.Run.Remove().

Hope that helps.

0reactions
mstoffel-infraservcommented, Mar 28, 2019

The following function will reproduce the issue.

private static void OpenAndSearch(string filename)
        {
            //Open file
            WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filename, true);
            //Get main document part
            var docPart = wordprocessingDocument.MainDocumentPart;
            //go through paragraphs in document and highlight search text
            foreach (var paragraph in docPart.Document.Body.Descendants<Paragraph>())
            {
                HighLightText(paragraph, "612-000-0000");
            }
            //Close and save
            wordprocessingDocument.Close();
        }

  static void HighLightText(Paragraph paragraph, string text)
        {
            // Search for a first occurrence of the text in the text runs
            var found = paragraph
                .Descendants<Run>()
                .Where(r => !string.IsNullOrEmpty(r.InnerText) && r.InnerText != "\\s" && r.GetFirstChild<Text>() != null)
                .Select(r =>
                {
                    var runText = r.GetFirstChild<Text>();
                    int index = runText.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase);

            // 'Run' is a reference to the text run we found,
            // TextNode is a reference to the run's Text object,
            // 'TokenIndex` is the index of the search string in run's text
            return new { Run = r, TextNode = runText, TokenIndex = index };
                })
                .FirstOrDefault(o => o.TokenIndex >= 0);

            // Nothing found -- escape
            if (found == null || found.Run == null)
            {
                return;
            }

            // Create a node for highlighted text as a clone (to preserve formatting etc)
            var highlightRun = found.Run.CloneNode(true);

            // Add the highlight node after the found text run and set up the highlighting
            paragraph.InsertAfter(highlightRun, found.Run);
            highlightRun.GetFirstChild<Text>().Text = text;
            RunProperties runPro = new RunProperties();
            Highlight highlight = new Highlight { Val = HighlightColorValues.Yellow };
            Vanish vv = new Vanish();

            runPro.AppendChild(highlight);
            runPro.AppendChild(vv);
            highlightRun.InsertAt(runPro, 0);

            // Check if there's some text in the text run *after* the found text
            int remainderLength = found.TextNode.Text.Length - found.TokenIndex - text.Length;
            if (remainderLength > 0)
            {
                // There is some text after the highlighted section --
                // insert it in a separate text run after the highlighted text run
                var remainderRun = found.Run.CloneNode(true);
                paragraph.InsertAfter(remainderRun, highlightRun);
                var textNode = remainderRun.GetFirstChild<Text>();
                textNode.Text = found.TextNode.Text.Substring(found.TokenIndex + text.Length);

                // We need to set up this to preserve the spaces between text runs
                textNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
            }

            // Check if there's some text *before* the found text
            if (found.TokenIndex > 0)
            {
                // Something is left before the highlighted text,
                // so make the original text run contain only that portion
                found.TextNode.Text = found.TextNode.Text.Remove(found.TokenIndex);

                // We need to set up this to preserve the spaces between text runs
                found.TextNode.Space = new EnumValue<SpaceProcessingModeValues>(SpaceProcessingModeValues.Preserve);
            }
            else
            {
                // There's nothing before the highlighted text -- remove the unneeded text run
                paragraph.RemoveChild(found.Run);
            }
        }
Read more comments on GitHub >

github_iconTop Results From Across the Web

Paragraph.InsertAfter Invalid Operation Error in Textbox #580
Receiving an invalid operation error when calling Paragraph.InsertAfter when the paragraph is in a floating object/textbox.
Read more >
InvalidOperationException when assigning text to a TextField
InvalidOperationException exception, telling me that the object is already used in a different thread. So why do I get that exception and ...
Read more >
Insert a rich text box
If you want users to be able to insert formatted text, paragraph breaks, tables, photographs, or clip art in a data-entry field, you...
Read more >
Cross-Reference to Heading Text of Heading generates ...
Terrible workaround: Make all edits to the non-last word in the heading-styled paragraph. How can we simply and reliably cross-reference heading ...
Read more >
VBA code needed for paragraph and bold within text box– ...
I have been asked to add a text box to a global Macro and was able to find a ... as to how...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found