0

I have the following code:

    private void HighlightSyntax(string syntax)
    {
        Regex regex = null;

        switch (syntax)
        {
            case ".xml":
                regex = new Regex(@"<\/?[^>\/]*>");
                break;
        }

        if (regex != null)
        {
            Input.BeginUpdate();

            // I want to save scrollbar position here and then restore it
            // or maybe even disable it from being changed

            int lastIndex = Input.SelectionStart;
            int lastLength = Input.SelectionLength;

            Input.SelectAll();

            // gets matches
            var matches = regex.Matches(Input.Text).Cast<Match>().ToArray();
            if (matches.Length > 0) // divide into tasks and select all matches
            {
                Color color = Color.ForestGreen;
                int wordsPerTask = 500;
                int tasksAmount = (matches.Length / wordsPerTask) + 1;
                int start = 0;
                int end = matches.Length - 1;

                Task[] tasks = new Task[tasksAmount];
                for (int i = 0; i < tasksAmount; i++)
                { // dividing
                    start = matches.Length / tasksAmount * i;
                    end = matches.Length / tasksAmount * (i + 1) - 1;

                    var start1 = start;
                    var end1 = end;
                    tasks[i] = Task.Run(() => { SelectMatchesInArr(matches, start, end, color); } );
                }

                if (matches.Length - 1 - end > 0)
                    SelectMatchesInArr(matches, end + 1, matches.Length - 1, color);

                Task.WaitAll(tasks);
            }

            Input.Select(lastIndex, lastLength);
            Input.SelectionColor = Color.Black;

            // Restore Input.ScrollBarPosition here

            Input.EndUpdate();
        }
    }

    // selects matches from start to end Indexes with Color color.
    private void SelectMatchesInArr(Match[] matches, int startIndex, int endIndex, Color color)
    {
        for (int i = startIndex; i <= endIndex; i++)
        {
            int selectionStart = Input.SelectionStart;

            lock (_locker)
            {
                Input.Select(matches[i].Index, matches[i].Length);
                Input.SelectionColor = color;

                Input.DeselectAll();
                Input.SelectionStart = selectionStart;
                Input.SelectionLength = 0;
            }
        }
    }

It highlights syntax in richtexbox, if regex matches anything related to that syntax. It all worked until I decided to divide selecting into multiple tasks.

After dividing the selection into multiple tasks, my scrollbar position is not stable. Well, I want it to be stable, I don't want it to be changed via code. How do I prevent it from being changed if I have multiple tasks manipulating over richtextbox? What should I do in my situation? Also check comments in the code, they are written in order to help you explain what I want to do.

By the way, the BeginUpdate() and EndUpdate() methods are extension methods that have been taken from here: Hans Passant's derived from richtextbox class

  • What's the actual use of this, since, in the end, you `WaitAll` the tasks? Which looks pretty useless. Btw, in your `SelectMatchesInArr` you are first selecting, then deselecting all (?). Also, all these: `int selectionStart = Input.SelectionStart; Input.DeselectAll(); Input.SelectionStart = selectionStart; Input.SelectionLength = 0;` you can remove. You just need `Select()` and `SelectionColor`. If you really want to use Task (which, give or take, defeats the purpose of having a custom `BeginUpdate` and `EndUpdate` methods), you have to `BeginInvoke` a UI Control. – Jimi Feb 12 '19 at 15:02

1 Answers1

1

Maybe it would be better to use multithreading only for generating the list of matches and then use them for highlighting?

Also, it seems a bit dangerous to modify UI in multiple threads without any synchronization since it's possible that one thread would call 'Input.Select' and the other one 'Input.DeselectAll' before the first one will set the color. Applying UI changes in one thread would eliminate that possibility.

Ivan
  • 343
  • 2
  • 7
  • Text highlighting in RichTextBox in WinForms is very unefficient. Hence, it's a normal way of using multithreading... And it would appear, the bug i've described in my question has been there even before I divided it all into multiple threads :D However the scrollbar position saving question sill remains.. – Марк Павлович Feb 12 '19 at 13:01
  • I edited my SelectMatchesInArr code, added locker, check in the question. Does that make it all thread-safe? And don't we lose that benefit from multithreading by using locker? – Марк Павлович Feb 12 '19 at 13:11
  • Yes, that does the code thread-safe, but as you mentioned that diminishes the idea of multithreading. In general, editing the same UI element from multiple threads is not a good practice. – Ivan Feb 12 '19 at 14:44
  • RichTextBox has a property Rtf that contains the formatted text. Maybe you would be able to find a third-party library that can work with RTF then you can prepare the changes and then just update RichTextBox.Rtf with a new value. If there is no such a library - here's a crutch: in 'HighlightSyntax' you can create another RichTextBox, set its Rtf to Rtf of the original one, then make all the necessary formatting in your local RichTextBox and at the end copy its Rtf content to the one on UI. It doesn't seem like a perfect solution since it'll consume more memory than it should, but it'll work. – Ivan Feb 12 '19 at 14:54