Thread-safe updates of a WinForm control from other classes

10,354

Solution 1

delegate can be used for Thread safe calls

Check this http://msdn.microsoft.com/en-us/library/ms171728.aspx

            // This delegate enables asynchronous calls for setting
    // the text property on a TextBox control.
    delegate void SetTextCallback(string text);

    // This method demonstrates a pattern for making thread-safe
    // calls on a Windows Forms control. 
    //
    // If the calling thread is different from the thread that
    // created the TextBox control, this method creates a
    // SetTextCallback and calls itself asynchronously using the
    // Invoke method.
    //
    // If the calling thread is the same as the thread that created
    // the TextBox control, the Text property is set directly. 

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.textBox1.InvokeRequired)
        {   
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox1.Text = text;
        }
    }

Solution 2

Typically you should run this kind of time-consuming operations in a BackgroundWorker. Define a work method:

private void worker_DoWork(object sender, DoWorkEventArgs e)
{   
    // execute your WriteOutput method
}

and set is as the DoWork event handler:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync(); // start the worker

To safely update the UI from a different thread use the Control.BeginInvoke method:

mainForm.BeginInvoke(
   () => { mainForm.UpdateLog(<text>); });

Solution 3

As suggested by Sonu, delegate can be used for Thread safe calls, and you can use Linq to shorten the code:

this.BeginInvoke( (Action) delegate ()
{
       //code to update UI
});

See this link for more information.

Share:
10,354
Luke G
Author by

Luke G

Updated on June 18, 2022

Comments

  • Luke G
    Luke G almost 2 years

    Could someone please help me with the following problem:

    There are two classes MainForm and LWriter. Below is a method from the LWriter that in addition to writing to a file sends some updates to a RichTextBox control (through mainForm.UpdateLog(text)). Everything works fine, however, this WriteOutput method also does some extensive processing that during the calculation freezes the form.

    I think the WriteOutput should be encapsulated in a separate thread. Could someone please help me out explaining how to place WriteOutput (LWriter class) in a thread that will then call mainForm.UpdateLog() from the mainFrom in a safe manner?

    I am new to threads, thus help would be much appreciated.

    public void WriteOutput(string output, Links[] links)
    {
       try {
          using (StreamWriter sw = new StreamWriter(output)) {
             for (int x= 1; x<links.Length;x++) {
           ...
               sw.WriteLine( ... );
               sw.Flush();                              
             }
             mainForm.UpdateLog(<text>);
          }
       } catch(Exception e) { ... }
    }
    
  • AH.
    AH. about 9 years
    By far the most elegant solution. Thanks.