Dealing with controls within a multi threaded context


Many people don't pay attention to the fact that controls couldn't be directly invoked within a thread context other than the one within which they have been created. And then their applications fall down because a run time error will be raised when firing the application. It is technically called none valid cross thread operation. It generates an InvalidOperationException.

As explanation to this error, I can say that each thread has its proper boundary exactly like a state that has a boundary. And it is not legal to travel from a county to another one without achieving some administrative tasks. It is exactly the same fact from an analogical point of view.

Therefore, it is not possible for a control that has been created within a given thread to be directly used within another thread event when one try to avoid the problem by using a Backgroundworker he/she won't resolve the problem if he/she doesn't have a complete idea about dealing with controls and or objects within a multithreaded contexts.

There are many used techniques in order to resolve the problem and I will represent one of those techniques.
But first let's see what will happen when an invalid cross threaded operation is designed and tested:

First, create a new windows application project and add a progress bar, a button and a label into the form1 so that it appears as under:

Add the namespace

using System.Threading;

Then try this code

public partial class Form1 : Form
    {

        Thread myThread;
        public Form1()
        {
            InitializeComponent();

                      myThread = new Thread(new ThreadStart(ModifyControlsState));
        }

   public void ModifyControlsState()
    {
       progressBar1.Minimum = 0;
       progressBar1.Maximum = 100;
      for (int i = 0; i <= 100; i = i + 1)
      {
       progressBar1.Increment(i);
       label1.Text = progressBar1.Value.ToString() + "%omplete"Thread.Sleep(10);
      }
      DialogResult dlg = MessageBox.Show("Do you want to close this window",
                                      "Do you want to exit this window",
                                              MessageBoxButtons.OKCancel);
     if (dlg == DialogResult.OK) Application.Exit();    }

     private void button1_Click(object sender, EventArgs e)
    
{
            myThread.Start();
        }

If you click the button1 you will receive this error:



Figure1

Now the solution is performed through the following steps:

  1. Add a void delegate class with the same characteristics conforming to the thread method signature
     

    private delegate void MyDelegate();

    MyDelegate myDelegate;
     
  2. Add a method with the same signature as the thread method except the name Of Corse

    public void Perform()
    {
      //TO DO: Cut the thread method implementation and paste it here

    }
     

  3. Create a new delegate instance that points to the Perform method

    private void Form1_Load(object sender, EventArgs e)
    {
      myDelegate = new MyDelegate(Perform);

    }
     

  4. Cut and paste the thread method implementation within the Perform method zone as follow

    public void Perform()
    {
                //TO DO: Cut the thread method implementation and paste it here
                progressBar1.Minimum = 0;
                progressBar1.Maximum = 100;
                    for (int i = 0; i <= 100; i = i + 1)
                    {
                        progressBar1.Increment(i);
      label1.Text = progressBar1.Value.ToString() + "%omplete";
      Thread.Sleep(10);
                    }
     DialogResult dlg = MessageBox.Show("Do you want to close this window",
                                       "Do you want to exit this window",
                                               MessageBoxButtons.OKCancel);
     if (dlg == DialogResult.OK) Application.Exit();

     }
     

  5. And finally, you add this code within the thread method zone

    public void ModifyControlsState()
    {
                Form1 form1 = this;
                form1.Invoke(myDelegate);
    }



    Figure 2

It works great, that's it.
Good Dotneting!!!