我们有一个DLL来监控状态的变化,并从单独购买的产品中查找事件。实际上,它是西门子的ScreenPop API,对于那些可能知道它是什么的人来说。我使用C#.NET 3.5作为平台。
这个API需要很长的时间来初始化,所以我们想要使用一个单独的线程来初始化它。目前,我们在名为ScreenPop的类中具有该功能。该类监视2个事件,状态更改事件和屏幕弹出事件(数据告诉我们客户是谁正在呼叫)。
目前实施的方式不起作用,或者至少不能可靠地运作。在ScreenPop类中,有一个初始化方法,其中放置了所有长时间运行的启动代码。这是从类的构造函数中调用的,如下所示:
public ScreenPop( string Address, int Ext, CallbackStatusType pStatusFunc,
CallbackScreenPopType pPopFunc
)
{
CallbackStatus = pStatusFunc;
CallbackPopup = pPopupFunc;
Thread t = new Thread( StartInBackground );
t.Start();
}
在GUI代码中,pStatusFunc处的func更新状态标签,pPopupFunc处的func将触发其他一些代码来弹出屏幕 - 现在它只显示事件中的数据。
缺少很多胶水,但我希望你明白这一点。这种方法的问题是GUI没有更新。我知道事件激活和事件处理程序运行,并且回调函数被调用,它们似乎应该运行,但GUI永远不会更新。
所以,我的问题是,我是否应该放弃支持BackgroundWorker方法呢?或者我只是遗漏了让GUI更新的内容?
有关要求的更多信息...... 谢谢, 戴夫
答案 0 :(得分:3)
您永远不能从另一个线程更新GUI - 只能从启动应用程序的UI线程更新。您需要使用Control.Invoke方法在UI线程上运行代码。表单实例,frmMain.Invoke。
答案 1 :(得分:2)
你不能在多线程公寓中使用WinForms
来解决这个问题,你必须编组到UI线程来对其执行操作或获得结果。由于您使用的是C#3.5,因此您可以使用lambda,泛型和扩展方法来制作一个非常简洁易用的解决方案。
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);
}
}
}
现在,您可以安全轻松地进行更改或获取价值。
this.InvokeEx(f => f.label1.Text = "Hello from another thread");
new Thread(() =>
{
string formTitle = this.InvokeEx(f => f.Text); // Safely get form title
}).Start();