【问题标题】:Calling UI method from a separate thread with no reference to UI controls从不引用 UI 控件的单独线程调用 UI 方法
【发布时间】:2012-08-05 08:03:09
【问题描述】:

我有一个公开公共事件的类。 GUI 上有各种控件可以使用此事件注册其事件处理程序以更改控件,例如文本或背景颜色等。但是,公开事件的类不会保留对那些可能具有的 UI 控件的任何引用添加了他们的事件处理程序。

在执行期间,一个单独的前台线程执行一个方法,该方法将调用(触发)公共事件。这将调用已注册到事件的事件处理程序。

问题在于事件处理程序是在前台线程而不是 UI 线程上调用的。如何在不引用 UI 控件的情况下编组对 UI 线程的调用?

【问题讨论】:

    标签: c# user-interface multithreading


    【解决方案1】:

    您需要决定要进行什么编组:事件引发器或事件处理程序。如果您不希望事件引发者了解有关线程的任何信息 - 例如通过ISynchronizeInvokeSynchronizationContext - 然后让事件处理程序执行编组。

    基本上,事件引发者应该保证它会在特定上下文中引发所有事件(可以通过SynchronizationContext 在构造时将其提供给它),或者应该明确说明它是不是这样做,并将责任放在处理程序身上。后者是更灵活的方法 - 这意味着如果您有多个具有不同需求的处理程序,每个处理程序都可以根据自己的需要做适当的事情。

    【讨论】:

      【解决方案2】:

      如果您关心的是将事件调用编组到您的(唯一)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);
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        您可以使用 Application.OpenForms() 获取打开的表单。

        Form form = System.Windows.Forms.Application.OpenForms().FirstOrDefault();
        if (form != null)
            form.Invoke((MethodInvoker)delegate(){ event(); });
        

        【讨论】:

          猜你喜欢
          • 2012-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多