在主 UI 线程上引发 .NET 中的事件 [英] Raise Events in .NET on the main UI thread

查看:19
本文介绍了在主 UI 线程上引发 .NET 中的事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 .NET 中开发一个类库,其他开发人员最终会使用它.该库使用了一些工作线程,并且这些线程会触发状态事件,这些事件将导致在 WinForms/WPF 应用程序中更新某些 UI 控件.

I'm developing a class library in .NET that other developers will consume eventually. This library makes use of a few worker threads, and those threads fire status events that will cause some UI controls to be updated in the WinForms / WPF application.

通常,对于每次更新,您都需要检查 WinForms 上的 .InvokeRequired 属性或等效的 WPF 属性,并在主 UI 线程上调用它以进行更新.这可能很快就会过时,让最终开发人员这样做感觉有些不对劲,所以...

Normally, for every update, you would need to check the .InvokeRequired property on WinForms or equivalent WPF property and invoke this on the main UI thread for updating. This can get old quickly, and something doesn't feel right about making the end developer do this, so...

有什么方法可以让我的库从主 UI 线程触发/调用事件/委托?

特别是...

  1. 我应该自动检测"要使用的主"线程吗?
  2. 如果不是,我是否应该要求最终开发人员在应用程序启动时调用一些(伪)UseThisThreadForEvents() 方法,以便我可以从该调用中获取目标线程?
  1. Should I automatically "detect" the "main" thread to use?
  2. If not, should I require the end developer to call some (pseudo) UseThisThreadForEvents() method when the application starts so I can grab the target thread from that call?

推荐答案

您的库可以检查事件调用列表中每个委托的 Target,如果目标是 ISynchronizeInvoke,则将调用编组到目标线程:

Your library could check the Target of each delegate in the event's invocation list, and marshal the call to the target thread if that target is ISynchronizeInvoke:

private void RaiseEventOnUIThread(Delegate theEvent, object[] args)
{
  foreach (Delegate d in theEvent.GetInvocationList())
  {
    ISynchronizeInvoke syncer = d.Target as ISynchronizeInvoke;
    if (syncer == null)
    {
      d.DynamicInvoke(args);
    }
    else
    {
      syncer.BeginInvoke(d, args);  // cleanup omitted
    }
  }
}

另一种使线程契约更加明确的方法是要求您的库的客户端为他们希望您在其上引发事件的线程传入 ISynchronizeInvoke 或 SynchronizationContext.与秘密检查委托目标"方法相比,这为您的库的用户提供了更多的可见性和控制权.

Another approach, which makes the threading contract more explicit, is to require clients of your library to pass in an ISynchronizeInvoke or SynchronizationContext for the thread on which they want you to raise events. This gives users of your library a bit more visibility and control than the "secretly check the delegate target" approach.

关于您的第二个问题,我会将线程编组内容放在您的 OnXxx 或用户代码调用的任何可能导致引发事件的 API 中.

In regard to your second question, I would place the thread marshalling stuff within your OnXxx or whatever API the user code calls that could result in an event being raised.

这篇关于在主 UI 线程上引发 .NET 中的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆