C#: Thread safe richtextbox event logging method?

c#
10,086

Try something like this:

public void LogTextEvent(RichTextBox TextEventLog, Color TextColor, string EventText)
{
    if (TextEventLog.InvokeRequired)
    {
        TextEventLog.BeginInvoke(new Action(delegate {
            LogTextEvent(TextEventLog, TextColor, EventText);
        }));
        return;
    }

    string nDateTime = DateTime.Now.ToString("hh:mm:ss tt") + " - ";

    // color text.
    TextEventLog.SelectionStart = TextEventLog.Text.Length;
    TextEventLog.SelectionColor = TextColor;

    // newline if first line, append if else.
    if (TextEventLog.Lines.Length == 0)
    {
        TextEventLog.AppendText(nDateTime + EventText);
        TextEventLog.ScrollToCaret();
        TextEventLog.AppendText(System.Environment.NewLine);
    }
    else
    {
        TextEventLog.AppendText(nDateTime + EventText + System.Environment.NewLine);
        TextEventLog.ScrollToCaret();
    }
}

If the LogTextEvent method is called from a thread other than the rich text box's UI thread, it will post a message to the UI thread which will cause the LogTextEvent method to be called in that thread.

By using BeginInvoke instead of Invoke, it is posted asynchronously which means that it returns immediately to the caller instead of waiting for the method to be executed on the other thread. For a logging scenario like this, this is probably what you want. If you needed to get a value from a control or something you would probably need to use Invoke instead.

Share:
10,086

Related videos on Youtube

Admin
Author by

Admin

Updated on May 02, 2022

Comments

  • Admin
    Admin almost 2 years

    I have a method that is meant to display output on a RichTextBox in a form.

        public void LogTextEvent(RichTextBox TextEventLog, Color TextColor, string EventText)
        {
            string nDateTime = DateTime.Now.ToString("hh:mm:ss tt") + " - ";
    
            // color text.
            TextEventLog.SelectionStart = TextEventLog.Text.Length;
            TextEventLog.SelectionColor = TextColor;
    
            // newline if first line, append if else.
            if (TextEventLog.Lines.Length == 0)
            {
                TextEventLog.AppendText(nDateTime + EventText);
                TextEventLog.ScrollToCaret();
                TextEventLog.AppendText(System.Environment.NewLine);
            }
            else
            {
                TextEventLog.AppendText(nDateTime + EventText + System.Environment.NewLine);
                TextEventLog.ScrollToCaret();
            }
        }
    

    The problem arises when I call LogEventText() from another method running inside a thread:

                Thread thListening = new Thread(new ThreadStart(StartListening));
                thListening.Start();
    

    Inside the StartListening method (it is a thread created that handles new tcp sockets to be created for clients on a main listening socket for a small http server), I make use of LogTextEvent to log some data, but I receive an InvalidOperationException was unhandled error in the LogTextEvent method at the 2nd line, TextEventLog.SelectionStart = TextEventLog.Text.Length;

    The error reads, Cross-thread operation not valid: Control 'rchEventLog' accessed from a thread other than the thread it was created on.

    Can anyone help break down what's going on, why, and how the error could be fixed?

  • Pure.Krome
    Pure.Krome over 15 years
    PERFECT! this solved my problem also. Resharper said i could make it a lamda (which i find reads nicer) ==> TextEventLog.BeginInvoke(new Action(() => LogTextEvent(TextEventLog, TextColor, EventText))));