Winforms exception Cross-thread operation not valid

0 votes
asked Jul 14, 2013 in Winforms by xavier

I am working on a windows application and I am new to this winforms. I have a scenario something like updating a progress bar based on the long running process status. I have given a small scenario here and if I can get the answer for this, I should be able to do the same in my real application as well. Once I run this, I am getting the exception

Cross-thread operation not valid: Control 'pbStatus' accessed from a thread other than the thread it was created on.

Please help me to fix this issue.

public partial class Form1 : Form
{
 public Form1()
 {
  InitializeComponent();
  pbStatus.Maximum = 20;
 }
 private void btnStart_Click(object sender, EventArgs e)
 {
  new Thread(new ThreadStart(Process)).Start();
 }
 private void Process()
 {
  for (int i = 0; i < 20; i++)
  {
    System.Threading.Thread.Sleep(100);
    UpdateProgressBar(value)
  }
 }
 private void UpdateProgressBar(int value)
 {
   pbStatus.Value = (int)value;
 }
}
Share

1 Answer

+1 vote
answered Jul 15, 2013 by Aadhira (1,213 points)
selected Jul 15, 2013 by administrator
 
Best answer

You are getting this exception because your progress bar is in UI thread and the Process method in another thread. When you called the Process method using new Thread, it created a separate thread to run the Process method. So, when you called UpdateProgressBar method from inside the Process method, it is throwing exception because ProgressBar is in UI thread.

To solve this issue, you need to check whether the current thread is different than the UI thread. If so, we need to change the control flow to UI thread to update it.

This can be done by using a property call "InvokeRequired". This property will be true if the current thread is not a UI thread. You can check this property on any control you want to update or may be you can check this on the form instance itself by using "this" keyword in C#.

Once we checked we need to call UpdateProgressBar using BeginInvoke. BeginInvoke will pass the thread control to UI. But, the BeginInvoke method will be expecting a delegate instead of your method.

So, you need to create a delegate and that delegate should match with the signature of the method you are going to call. In your case, it is going to be

void UpdateProgressBar(int value)

So create a delegate like below.

delegate void UpdateProgressBarHandler(int status);

Once you do that, then you can create the instance of the delegate and pass your method as the parameter. This delegate instance can be passed as a parameter to the BeginInvoke method. Since your delegate is accepting "int" parameter, you can pass integer value. I have put together the code and give below. Now everything should work fine.

public partial class Form1 : Form
{
    delegate void UpdateProgressBarHandler(int status);

    public Form1()
    {
        InitializeComponent();
        pbStatus.Maximum = 20;
    }
    private void btnStart_Click(object sender, EventArgs e)
    {
        new Thread(new ThreadStart(Process)).Start();
    }
    private void Process()
    {
        for (int i = 0; i < 20; i++)
        {
            System.Threading.Thread.Sleep(100);
            CheckForCrossThread(i+1);
        }
    }
    private void CheckForCrossThread(int value)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new UpdateProgressBarHandler(UpdateProgressBar), new object[] { value });
        }
    }
    private void UpdateProgressBar(int value)
    {
        pbStatus.Value = (int)value;
    }
}

Your answer

Preview

Your name to display (optional):
Privacy: Your email address will only be used for sending these notifications.
Anti-spam verification:
To avoid this verification in future, please log in or register.
site design / logo / content © 2013 - 2015 pinfaq.com
...