0

Let's say, I have two buttons on a windows form. When I press button1, I use an AutoResetEvent called wh inside a new thread th in order to wait. When I press button2, I do wh.Set() so that my thread th is unlocked. Here is my class to illustrate this:

public partial class Form1 : Form
{
    AutoResetEvent wh = new AutoResetEvent(false);
    Thread th;

    public Form1()
    {
        InitializeComponent();
    }

    public void button1_Click(object sender, EventArgs e)
    {
        th = new Thread(thread);
        th.Start();
    }

    public void thread()
    {
        MessageBox.Show("waiting..");
        wh.WaitOne();
        MessageBox.Show("Running..");
    }

    private void button2_Click(object sender, EventArgs e)
    {
        wh.Set();
    }
}

This is working as wanted. But my problem is that I can't access, let's say a label or any other control, from my thread th..

public partial class Form1 : Form
{
    AutoResetEvent wh = new AutoResetEvent(false);

    public Form1()
    {
        InitializeComponent();
    }

    Thread th;

    public void button1_Click(object sender, EventArgs e)
    {
        th = new Thread(thread);
        th.Start();
    }

    public void thread()
    {
        label1.Text = "waiting..";
        wh.WaitOne();
        label1.Text = "running..";
    }

    private void button2_Click(object sender, EventArgs e)
    {
        wh.Set();
    }
}

I get an error running this, saying that label1 is accessed from another thread.

So how can I access controls in my second thread, or modify my code to change the location of the wh.WaitOne, whithout blocking the main thread? Code examples are appreciated!

Aeder
  • 15
  • 5
  • Read about Contol's `InvokeRequired` property and `Invoke` method. – Zohar Peled Jan 17 '16 at 12:00
  • Possible duplicate of [Automating the InvokeRequired code pattern](http://stackoverflow.com/questions/2367718/automating-the-invokerequired-code-pattern) – rene Jan 17 '16 at 12:04

1 Answers1

0

This happen because the label is created on different thread and you can't change it directly. I Suggest you use BeginInvoke.

 AutoResetEvent wh = new AutoResetEvent(false);
    Thread th;

    private delegate void SetLabelTextDelegate(string text);
    public Form1()
    {
        InitializeComponent();
    }
    public void thread()
    {
        // Check if we need to call BeginInvoke.
        if (this.InvokeRequired)
        {
            // Pass the same function to BeginInvoke,
            this.BeginInvoke(new SetLabelTextDelegate(SetLabelText),
                                             new object[] { "loading..." });
        }
        wh.WaitOne();

    }

    private void SetLabelText(string text)
    {
        label1.Text = text;
    }
Saifeddine M
  • 483
  • 1
  • 5
  • 14
  • Thanks for answering so quickly! This works, but isn't there some sort of workaround to shorten this? Mainly because in my real code I got many controls to access many times. – Aeder Jan 17 '16 at 12:33
  • Well, in recommend you use [BackgroundWorker](https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx) rather than native threads because it's designed to be used in this kind of situations – Saifeddine M Jan 17 '16 at 12:40