我正在写一个小聊天应用程序,我有这个事件处理程序:
void o_Typing(object sender, EventArgs e)
{
MessageBox.Show("Fired!");
this.Text = "Fired!";
}
o_Typing
是从TabPage
派生的类中的方法。基本上,我希望每个对话都有自己的标签。
事件处理程序由我的Chat对象触发,该对象在另一个线程中运行。我有一个用于UI的线程,另一个用于每个聊天对话的线程(用于轮询服务器以获取新数据)
当事件被触发时,弹出MessageBox
,但Tab标题不会改变。事件触发一次之后,它再也不会触发,导致我相信在工作线程中调用了事件,尽管它是在UI线程中定义的。
如何从工作线程调用我的事件,并使用Invoke()
让它们在UI线程上执行?
答案 0 :(得分:11)
有两种选择:
1)使事件处理程序是线程安全的:在任何需要与UI线程通信的事件处理程序中使用Control.Invoke/BeginInvoke
。
2)在引发事件之前,将工作线程封送回UI线程 - 换句话说,在引发事件的过程中使用Control.Invoke
,以便全部调用事件处理程序UI线程。根据您的应用程序的结构,您可能不希望您的事件提升组件明确了解UI - 但是在构建它时,您可以传入ISynchronizeInvoke
(Control
实现)和您的组件可以使用它来在正确的线程上引发其事件。当然,如果每个事件处理程序都乐于在同一个线程上运行,那么这只会起作用(简单地说,无论如何) - 但通常情况就是如此。你会写一些类似的东西:
protected void OnFoo(EventArgs args)
{
if (sync != null && sync.InvokeRequired)
{
sync.Invoke((Action) delegate { OnFoo(args) }, null);
return;
}
EventHandler handler = Foo; // Where Foo is the event name
if (handler != null)
{
handler (this, args);
}
}
答案 1 :(得分:6)
如果您在工作线程执行的代码中触发事件,那么订阅该事件的所有方法都将在该工作线程下执行。
对于GUI元素,您需要查看Invoke-methods。
最好的问候