简体   繁体   中英

GUI update when starting event handler class on separate thread?

We have a DLL that monitors changes in status and looks for events from a separate, purchased product. Actually, it is a ScreenPop API from Siemens, for those of you who may know what that is. I am using C#.NET 3.5 as the platform.

This API takes a looong time to initialize, so we want to use a separate thread to initialize it. Currently, we have the functionality in a class called ScreenPop. The class monitors 2 events, a status change event and a screen pop event (data that tells us who the customer is that is calling).

The way this is currently implemented doesn't work, or at least doesn't work reliably. Within the ScreenPop class, there is an initialization method where all the long-running startup code is placed. This is called from the constructor of the class, like this:

public ScreenPop( string Address, int Ext, CallbackStatusType pStatusFunc,
      CallbackScreenPopType pPopFunc 
)
{
    CallbackStatus = pStatusFunc;
    CallbackPopup = pPopupFunc;

    Thread t = new Thread( StartInBackground );
    t.Start();
}

In the GUI code, the func at pStatusFunc updates a status label, and the func at pPopupFunc will fire off some other code to do the screen pop - right now it just displays the data from the event.

There is a lot of glue missing, but I hope you get the point. The problem with this approach is the GUI is not updated. I know the events fire and the event handlers run, and the callback functions are getting called and they seem like they should be running, but the GUI is never updated.

So, my question is, should I abandon this in favor of a BackgroundWorker approach? Or am I just missing something in getting the GUI to update?

More info on request... Thanks, Dave

You can never update the GUI from a different thread - only from the UI thread, which is the one that started the application. You need to use the Control.Invoke method to run code on the UI thread. Form instance, frmMain.Invoke.

You cannot use WinForms in a multithreaded apartment, to get around this, you have to marshal over to the UI thread to perform actions on it or get results. Since you are using C#3.5, you can make use of lambdas, generics, and extension methods to make a really clean and easy to use solution.

public static class ControlExtensions
{
  public static TResult InvokeEx<TControl, TResult>(this TControl control,
                            Func<TControl, TResult> func)
    where TControl : Control
  {
    if (control.InvokeRequired)
    {
      return (TResult)control.Invoke(func, control);
    }
    else
    {
      return func(control);
    }
  }
}

Now you can safely and easily make changes or get values.

this.InvokeEx(f => f.label1.Text = "Hello from another thread");

new Thread(() =>
  {
    string formTitle = this.InvokeEx(f => f.Text); // Safely get form title
  }).Start();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM