我有一个公开公共事件的类。GUI 上有各种控件可以使用此事件注册其事件处理程序以更改控件,例如文本或背景颜色等。但是,公开事件的类不会保留对那些可能具有的 UI 控件的任何引用添加了他们的事件处理程序。
在执行期间,一个单独的前台线程执行一个方法,该方法将调用(触发)公共事件。这将调用已向事件注册的事件处理程序。
问题是事件处理程序是在前台线程而不是 UI 线程上调用的。如何在不引用 UI 控件的情况下编组对 UI 线程的调用?
我有一个公开公共事件的类。GUI 上有各种控件可以使用此事件注册其事件处理程序以更改控件,例如文本或背景颜色等。但是,公开事件的类不会保留对那些可能具有的 UI 控件的任何引用添加了他们的事件处理程序。
在执行期间,一个单独的前台线程执行一个方法,该方法将调用(触发)公共事件。这将调用已向事件注册的事件处理程序。
问题是事件处理程序是在前台线程而不是 UI 线程上调用的。如何在不引用 UI 控件的情况下编组对 UI 线程的调用?
你需要决定什么是编组:事件引发者或事件处理程序。如果您不希望事件引发者了解有关线程的任何信息 - 例如通过ISynchronizeInvoke
或SynchronizationContext
- 然后让事件处理程序改为执行编组。
基本上,事件引发者应该保证它会在特定上下文中引发所有事件(可以在构造时通过 给予它SynchronizationContext
)或者它应该明确表示它没有这样做,并将责任放在处理程序上。后者是更灵活的方法 - 这意味着如果您有多个具有不同需求的处理程序,每个处理程序都可以根据自己的需要做适当的事情。
如果您关心的是将事件调用编组到您的(唯一)UI 线程,那么这ISynchronizeInvoke
就是您所需要的。
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form mainForm = new MyForm();
// Initialize the service.
MyService service = new MyService(mainForm);
Application.Run(mainForm);
}
public class MyService
{
public event EventHandler MyEvent;
private readonly ISynchronizeInvoke synchronizeInvoke;
public MyService(ISynchronizeInvoke synchronizeInvoke)
{
this.synchronizeInvoke = synchronizeInvoke;
}
private void OnMyEvent()
{
if (MyEvent != null)
{
if (synchronizeInvoke.InvokeRequired)
{
synchronizeInvoke.BeginInvoke(new Action(() => MyEvent(this, EventArgs.Empty)), null);
}
else
{
MyEvent(this, EventArgs.Empty);
}
}
}
}
您可以使用 Application.OpenForms() 获取打开的表单。
Form form = System.Windows.Forms.Application.OpenForms().FirstOrDefault();
if (form != null)
form.Invoke((MethodInvoker)delegate(){ event(); });