JJalenak
JJalenak

Reputation: 123

Call method on worker thread FROM the UI thread

Working in Winforms with C#, I have a main form that creates a second UI form on a separate thread.

viewThread = new Thread( ( ) => 
{ 
  views = new Views.Views( displayRotators, screenLocationLeft, screenLocationTop, screenHeight, screenWidth );
  Application.Run( views );
} );
viewThread.SetApartmentState( ApartmentState.STA );
viewThread.Start( );

On the second UI form, I now need to invoke a method to start a display loop that will run until I terminate the thread. I've spent about three hours trying to find a way to do this, but all I can find are examples of calling methods on the main UI thread from the worker thread, not calling methods on the worker thread FROM the main UI thread. Can anyone tell me how I can do this?

Thanks.

Upvotes: 0

Views: 1662

Answers (2)

Boppity Bop
Boppity Bop

Reputation: 10463

a. there is nothing wrong with using multiple UI threads if you know what you do.

b. it is incorrect and confusing calling a UI thread worker - UI thread #2 is same as #1 from the developer standspoint. once you realize it - many problem will clear themselves.

c. if you want to call view2.SomeMethod() [run in UI thread #2] from view1 [run in UI thread #1] - call BeginInvoke on the view2.

The code below is simple to adopt. button1 - launches the second UI thread. button2 - calls method from UI thread 1 on the form which is in UI thread 2

    Form2 form;
    private void button1_Click(object sender, EventArgs e)
    {
        Thread viewThread = new Thread(() =>
        {
            form = new Form2();
            Application.Run(form);
        });
        viewThread.SetApartmentState(ApartmentState.STA);
        viewThread.Start();

        label1.Text = Thread.CurrentThread.ManagedThreadId.ToString();

    }

    private void button2_Click(object sender, EventArgs e)
    {
        if (form != null)
        {
            form.BeginInvoke(new Action(() => 
                {form.Method("Form1 is calling...");}));
        }
    }

in the form 2 :

    public void Method(string s)
    {
        label1.Text = string.Format("{0} '{1}'", 
                        Thread.CurrentThread.ManagedThreadId, s);
    }

you will see that the thread number is different and yet the string has crossed them OK.

Upvotes: 0

Eric J.
Eric J.

Reputation: 150108

There are very few cases where running multiple UI threads really makes sense. Unless you have a very compelling reason to do that, I would go back to a single UI thread.

Assuming you must have multiple UI threads, the golden rule is that Controls may only be updated from the UI thread they were created on.. If you want to call methods in general, you do not have to marshal them at all. However, if those methods in turn interact with a UI control, you would just marshal that call exactly the same way you would if the call were from any other thread that is not the UI thread belonging to the control.

If you might have something like

btnOnForm1OnUIThread1_Click(...)
{
    UpdateForm2OnUIThread2();
}

UpdateForm2OnUIThread2()
{
    if (control.InvokeRequired)
    {
      // Syntax of this line may be slightly off as I'm writing from memory ... 
      // I normally use an extension method
      control.Invoke(UpdateForm2OnUIThread2); 
    }
    else
    {
      control.Text = "Blah";
    }    
}

Upvotes: 3

Related Questions