cross - thread problem

A

Alistair George

if (e.Clicks > 0 && e.Button == MouseButtons.Middle)
{
f1.NewThread = new Thread(new
ThreadStart(f1.ShowMainNodes));
f1.NewThread.Start();
}

private void ShowMainNodes()
{
API.POINTAPI papi = new ALaunch.API.POINTAPI();
API.GetCursorPos(ref papi);
Point p = new Point(papi.x /*- this.Location.X*/ , papi.y
/*- this.Location.Y - 16*/);
this.Activate(); // x-thread error here - why; I thought
this was done in a thread-safe manner?
}


Thank you.
//System.InvalidOperationException was unhandled
Message="Cross-thread operation not valid: Control 'Form1' accessed
from a thread other than the thread it was created on."
Source="System.Windows.Forms"
StackTrace:
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Form.Activate()
at ALaunch.Form1.ShowMainNodes() in C:\Documents and
Settings\Alistair George\My Documents\Visual Studio
2005\Projects\Launcher\Form1.cs:line 335
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
 
N

Nicholas Paldino [.NET/C# MVP]

Alistair,

Well, doing it in a thread-safe manner is one thing, but in this case,
you are making one (possibly two) calls to the UI on a thred that is not the
UI thread.

You need to make the call to Activate on the same thread that the
control was created on. Also, and I am not sure, the call to GetCursorPos
might have to be made on the UI as well (although I can see why it might not
be required).
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

You cannot use a Control from a thread other than the UI thread.
In these cases you need to use Control.Invoke

You can use any control to be used as the "hook"
 
A

Alistair George

Nicholas said:
Alistair,

Well, doing it in a thread-safe manner is one thing, but in this case,
you are making one (possibly two) calls to the UI on a thred that is not the
UI thread.

You need to make the call to Activate on the same thread that the
control was created on. Also, and I am not sure, the call to GetCursorPos
might have to be made on the UI as well (although I can see why it might not
be required).
Ok, unfortunately, thats not clear - there is the old thread already
running, which I cant call as it conflicts with current mouse events,
hence the reason for starting a new thread. I dont call the old thread
from the new thread do I?
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

Alistair George said:
Thanks; how about some short examples for clarity.

Google Control.Invoke you will get a ton of examples as this is a VERY
recurrent question
 
N

Nicholas Paldino [.NET/C# MVP]

Alistair,

Well, yes, you could, by calling the Invoke method on the control, and
passing in a delegate which will execute the code on the UI thread.

The thing is, the code you have shown doesn't really do much, and
shouldn't intefere with the UI thread at all. It's very short, and doesn't
do much.
 
A

Alistair George

Ignacio said:
Hi,



Google Control.Invoke you will get a ton of examples as this is a VERY
recurrent question
Thanks. Should have thought of that - been up since 4am working on this
problem!
 
A

Alistair George

Nicholas said:
Alistair,

Well, yes, you could, by calling the Invoke method on the control, and
passing in a delegate which will execute the code on the UI thread.

The thing is, the code you have shown doesn't really do much, and
shouldn't intefere with the UI thread at all. It's very short, and doesn't
do much.
I notice that where the form F1 is instantiated, it also has Single
threaded [STAThread] set; is that a likely problem?
[STAThread]
static void Main()
{
Application.Run(f1);
}
 
N

Nicholas Paldino [.NET/C# MVP]

Alistair,

Well, it is the cause, but it's supposed to be there. It's a
fundamental windows programming tennant that you have to make calls to UI
components on the same thread that they were created. You are looking to
activate your form, so that call has to be made on the main thread.

If you remove that attribute, your program is going to stop working in a
number of other places really quick.

Now, there is no reason you can't get the cursor position and expose
those details to the worker thread, and then call Invoke to call a delegate
that will call Activate on your form when done.

Of course, I still don't see why you have to, as the code you have is
very small, and shouldn't take long to run at all.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Alistair George said:
Nicholas said:
Alistair,

Well, yes, you could, by calling the Invoke method on the control,
and passing in a delegate which will execute the code on the UI thread.

The thing is, the code you have shown doesn't really do much, and
shouldn't intefere with the UI thread at all. It's very short, and
doesn't do much.
I notice that where the form F1 is instantiated, it also has Single
threaded [STAThread] set; is that a likely problem?
[STAThread]
static void Main()
{
Application.Run(f1);
}
 
A

Alistair George

Nicholas said:
Alistair,
Invoke to call a delegate
that will call Activate on your form when done.

Of course, I still don't see why you have to, as the code you have is
very small, and shouldn't take long to run at all.
Cheers Nicholas. Your help appreciated. I am quite clueless when it
comes to this part of programming never having been there before. C# is
much more picky than Delphi used to be, but I can figure its for stability.
Am trying to get the middle mouse button to activate a form, as well as
hotkey combo (which is working well). Catching the middle mouse button,
but from there the problem area is.
An alternative could be to simulate a hotkey press to activate the form.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top