How to update a RichTextBox from BackgroundWorker using BeginInvoke

10,543

Solution 1

You need an else statement in your the UpdateResultsLine method. When Invoke is required, you are executing the UpdateResultsLine method using the delegate (invoking), but then you call again without using Invoke

Also, why do you use BeginInvoke (async) and use Invoke (sync)? Are you sure you have no sync problems? Using Invoke and adding an else statement could solve your problems:

private void UpdateResultsLine(string line, List<char> foundChars)
{
    if (txtResults.InvokeRequired)
    {
        txtResults.Invoke(
            new UpdateResultsLineDelegate(UpdateResultsLine),
            line,
            foundChars);
    }
    else
    {
        txtResults.AppendLine(
            line,
            foundChars,
            _fileType.ProcessColumns);
    }
}

Solution 2

Here what you can try, create the extension class as follows

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null);
        else action.Invoke();
    }
 }

And when ever and where ever you want to update anything on UI, you just need to do

 richTextBox.Invoke(() => { richTextBox.AppendText(text + Environment.NewLine); });

Hope this works for you.

Share:
10,543
BlueChippy
Author by

BlueChippy

Updated on June 05, 2022

Comments

  • BlueChippy
    BlueChippy almost 2 years

    I have a small app that reads in a pipe delimted file and writes out lines to a RTB, highlighting if there are dissallowed characters in certain "columns". This is working perfectly...however, the Users want a progress bar and to see the lines being written "live" and also to be able to cancel mid-way through.

    I have the following extension method that I have been using to write to a RichTextBox, while blocking the UI, but this fails using a BackgroundWorker with BeginInvoke.

    The fail is when finding the current length of the text.

    public static void AppendLine(this RichTextBox richTextBox, string text, List<Char> foundChars, List<int> columns)
            {
                var split = text.Trim().Split(new char[] { '|' });
    
                for (int i = 0; i < split.Count(); i++)
                {
                    **var start = richTextBox.TextLength;**
                    richTextBox.AppendText(split[i]);
                    var end = richTextBox.TextLength;
    
                    if (columns.Contains(i + 1))
                    {
                        foreach (var foundChar in foundChars)
                        {
                            var current = start;
    
                            while (current > 0)
                            {
                                var position = richTextBox.Find(new char[] { foundChar }, current, end);
                                current = position + 1;
                                if (current > 0)
                                {
                                    richTextBox.Select(position, 1);
                                    richTextBox.SelectionColor = Color.Red;
                                }
                            }
                        }
                    }
                    richTextBox.SelectionLength = 0;
                    richTextBox.SelectionColor = Color.Black;
                }
                richTextBox.AppendLine();
            }
    

    private void UpdateResultsLine(string line, List<char> foundChars)
            {
                if (txtResults.InvokeRequired)
                {
                    txtResults.BeginInvoke(new UpdateResultsLineDelegate(UpdateResultsLine), line, foundChars);
                }
                txtResults.AppendLine(line, foundChars, _fileType.ProcessColumns);
            }
    

    However, if I call any/all of these extensions in the same way, they work?

    public static void AppendLine(this RichTextBox richTextBox)
    {
        richTextBox.AppendText(Environment.NewLine);
    }
    
    public static void AppendLine(this RichTextBox richTextBox, string text)
    {
        richTextBox.AppendText(text + Environment.NewLine);
    }
    
    public static void AppendLine(this RichTextBox richTextBox, string text, params object[] args)
    {
        richTextBox.AppendLine(string.Format(text, args));
    }
    

    What am I missing? or is there another way to write coloured text to a RTB?

  • BlueChippy
    BlueChippy over 12 years
    I'd got half way by adding the "else" clause, but BeginInvoke -> Invoke sorted the rest for me. Thx
  • BlueChippy
    BlueChippy over 12 years
    Daniel answered first and I implemented his solution so he gets the points...however I might switch to this one as I like the clarity.
  • Kiquenet
    Kiquenet almost 12 years
    Maybe better BeginInvoke kristofverbiest.blogspot.com/2007/02/…
  • Sheikh M. Haris
    Sheikh M. Haris over 8 years
    Perfect solution for my case, as I have to update current progress in Rich Text Box. Thanks
  • Admin
    Admin over 5 years
    it also works with adding an item in a listbox --> myListBox.Invoke( ( ) => { myListBox.Items.Add( myListOfStrings[ i ] ); } );