views:

72

answers:

4

Hello!

I have a winform and some threads. When i try to access a field in the winform from one of the threads, the following error occurs : Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on.

How can i resolve this problem?

Regards, Alexandru Badescu

+2  A: 

In your Thread code, before changing textBox1, check textBox1.InvokeRequired and if so, use textBox1.Invoke(aDelegate)

Henk Holterman
I'll look for some links, this Q is a dupe.
Henk Holterman
so i've used the following code : 'public void setText(String a) { if (this.richTextBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(setText); this.Invoke(d, new object[] { a }); } else { this.richTextBox1.Text = a; }' }'
Badescu Alexandru
my question is, what does this code actually mean? what does it do?
Badescu Alexandru
and btw, the code works :)
Badescu Alexandru
@Badescu, "what does this code actually mean?" It means that when you're on another thread (InvokeRequired==true) then you have to Invoke your action to the MessageLoop. It will be executed on the UI thread.
Henk Holterman
understood! thanks!
Badescu Alexandru
+3  A: 

Tovarășe Alexandru,

All controls have a method called Invoke, which takes a delegate as the first argument and optional params object[].
You can use this method easily:

richTextBox1.Invoke(new MethodInvoker(DoSomething));  

where

void DoSomething()
{
    richTextBox1.BackColor = Color.Cyan;
}

The delegate MethodInvoker is in the System.Windows.Forms namespace, which, I suppose, you are already using.

You can even invoke from the same thread!

You can also use parameters, like this:

richTextBox1.Invoke(new ColorChanger(DoSomething), Color.Cyan);  

where

delegate void ColorChanger(Color c);

void DoSomething(Color c)
{
    richTextBox1.BackColor = c;
}

I hope this helped!

Edit:
BeginInvoke is required if you are using the same method from a... basically... unknown thread. So it would look like this:

void DoSomething()
{
    if (richTextBox1.InvokeRequired)
        richTextBox1.Invoke(new MethodInvoker(DoSomething));
    else
    {
        richTextBox1.BackColor = Color.Cyan;
        // Here should go everything the method will do.
    }
}

You may call this method from ANY thread!

And for parameters:

delegate void ColorChanger(Color c);

void DoSomething(Color c)
{
    if (richTextBox1.InvokeRequired)
        richTextBox1.Invoke(new ColorChanger(DoSomething), c);
    else
    {
        richTextBox1.BackColor = c;
        // Here should go everything the method will do.
    }
}

Enjoy programming!

Vercas
Multumesc mult Vercas! :D Very detailed ! +1
Badescu Alexandru
oh and another question! why are these invokes required? i mean, what is the purpose of using this kind of invokes? Why can't i just call directly ?
Badescu Alexandru
Ma bucur ca am putut fi de ajutor! Invokes basically run a delegate in the thread in which the control was created. I personally think this prevents application hacking.
Vercas
+2  A: 

Hi Alexandru,

what Vercas suggested works fine, but if you love inline code you may also try to choose an anonymous delegate

richTextBox1.Invoke(new MethodInvoker(
    delegate() {
        richTextBox1.BackColor = Color.Cyan;
    ));

+1 to him :)

djechelon
Thanks for the +1!
Vercas
+1  A: 

Salut Alexandru

You may want to check out an alternative way, the

BackgroundWorker

component. It is really easy and confortable to use. More details and samples you can find here

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

This component is also very important one in .NET and very usefull to know.

Liviu M.
multumesc! I'll look into it!
Badescu Alexandru