How to verify a big text in RichTextBox without freezing the screen?

207 Views Asked by At

I'm currently implementing a Custom Spell Check in WPF using NHunspell, because the native solution of .Net Framework doesn't fit my needs. But I'm having trouble when checking the words in a big text, such as a Lorem Ipsum with 10 pargraphs, because i need to check each word, see if it contains in the dictionary the Hunspell uses, and if not, I need to Underline that Word.

I have this current method, that checks all the text everytime the KeyUp is a Backspace or a Space Key.

var textRange = new TextRange(SpellCheckRichTextBox.Document.ContentStart, 
SpellCheckRichTextBox.Document.ContentEnd);
        textRange.ApplyPropertyValue(Inline.TextDecorationsProperty, null);
        _viewModel.Text = textRange.Text;
        var zzz = _viewModel.Text.Split(' ');
        var kfeofe = zzz.Where(x => _viewModel.MisspelledWords.Contains(x));
        foreach (var item in kfeofe)
        {
            TextPointer current = textRange.Start.GetInsertionPosition(LogicalDirection.Forward);

            while (current != null)
            {
                string textInRun = current.GetTextInRun(LogicalDirection.Forward);
                if (!string.IsNullOrWhiteSpace(textInRun))
                {
                    int index = textInRun.IndexOf(item.ToString());
                    if (index != -1)
                    {
                        TextPointer selectionStart = current.GetPositionAtOffset(index, LogicalDirection.Forward);
                        TextPointer selectionEnd = selectionStart.GetPositionAtOffset(item.ToString().Length, LogicalDirection.Forward);
                        TextRange selection = new TextRange(selectionStart, selectionEnd);

                        selection.ApplyPropertyValue(Inline.TextDecorationsProperty, TextDecorations.Underline);
                    }
                }
                current = current.GetNextContextPosition(LogicalDirection.Forward);
            }

        }

But, I think I need a Async solution, so it doesn't block my main thread and the typing of the user. - In theory I was thinking about running a parallel thread if the user spends more than 2 seconds without typing and then returning the checked TextRange to my RichTextBox (SpellCheckRichTextBox).

Can somebody suggest any solution so I can make the verification less slow when working with big texts? I'm really stuck at that, any help would be appreciated. Thanks in advance!

1

There are 1 best solutions below

0
nvoigt On

The first improvement would be

zzz.AsParallel().Where(x => _viewModel.MisspelledWords.Contains(x)).ToList();

That obviously assumes that your .MisspelledWords.Contains(x) is something that can be done in parallel. It might be a ConcurrentDictionary already.

The fact that you have a collection of misspelled words, makes me believe you already parsed the text once. So why parse it twice? Why can't you combine those two passes? That would be another possible optimization.

And yes, doing all of this in another thread when the user stops typing would be preferable.