简体   繁体   English

使用同步上下文将事件编组到ui线程

[英]marshalling events to ui thread using Synchronisation Context

All the examples I have seen using SynchronisationContext.Post have been used in the same class. 我在SynchronisationContext.Post中看到的所有示例均在同一类中使用。 What I have is the UI thread passing some by-ref arguments to a threadwrapper class, updating the arguments and then I want it to update some labels etc on the UIThread. 我所拥有的是UI线程,将一些by-ref参数传递给threadwrapper类,更新了参数,然后我希望它更新UIThread上的一些标签。

 internal class ConnThreadWrapper 
{
    ....

    public event EventHandler<MyEventArgs<String, Boolean>> updateConnStatus = 
        delegate { };

    public void updateUIThread(string conn, bool connected)
    {
        uiContext.Post(new SendOrPostCallback((o) => 
                           { 
                               updateConnStatus(this, 
                                  new MyEventArgs<String, Boolean>(conn, 
                                                                   connected));  
                           }), 
                       null);
    }
}


//on ui thread

 public void updateConnStatus(object sender, MyEventArgs<String, Boolean> e)
    {
        switch (e.val1)
        {
           case "CADS" :
           if (e.val2 == true)
           {

           }

The Event seems to fire without any errors but nothing is ever received on the uiThread - i'm not sure if my signature for the sub updateConnStatus is correct or if it works like this. 该事件似乎没有任何错误就触发了,但是在uiThread上什么也没收到-我不确定我对subupdateConnStatus的签名是否正确,或者它是否像这样工作。 I obviously want the event to handled on the uithread and update the labels from that sub. 我显然希望事件在uithread上处理并从该子目录更新标签。

In a previous vb.net project I used to reference the form directly on the thread and used a delegate to invoke a callback but apparently this was a bad design as I was mixing application layers. 在以前的vb.net项目中,我曾经直接在线程上引用该表单,并使用了一个委托来调用回调,但是显然这在我混合应用程序层时是一个糟糕的设计。 I wanted to use the sync context as it was meant to be thread safe but most of the examples i've seen have used invoke. 我想使用同步上下文,因为它本来是线程安全的,但是我看到的大多数示例都使用了invoke。

Any ideas what I'm missing? 有什么想法我想念的吗? Thanks 谢谢

I wrote this helper class which works for me. 我写了这个对我有用的助手类。 Prior to using this class call InitializeUiContext() on UI thread somewhere on application start. 在使用此类之前,请在应用程序启动时在UI线程上调用InitializeUiContext()。

   public static class UiScheduler
   {
      private static TaskScheduler _scheduler;
      private static readonly ConcurrentQueue<Action> OldActions = 
          new ConcurrentQueue<Action>();

      public static void InitializeUiContext()
      {
         _scheduler = TaskScheduler.FromCurrentSynchronizationContext();
      }

      private static void ExecuteOld()
      {
         if(_scheduler != null)
         {
            while(OldActions.Count > 0)
            {
               Action a;

               if(OldActions.TryDequeue(out a))
               {
                  UiExecute(_scheduler, a);
               }
            }
         }
      }

      private static void UiExecute(TaskScheduler scheduler, 
                                    Action a, 
                                    bool wait = false)
      {
         //1 is usually UI thread, dunno how to check this better:
         if (Thread.CurrentThread.ManagedThreadId == 1)  
         {
            a();
         }
         else
         {
            Task t = Task.Factory.StartNew(a, 
                                           CancellationToken.None,  
                                           TaskCreationOptions.LongRunning,  
                                           scheduler);

            if (wait) t.Wait();
         }         
      }

      public static void UiExecute(Action a, bool wait = false)
      {
         if (a != null)
         {
            if (_scheduler != null)
            {
               ExecuteOld();

               UiExecute(_scheduler, a, wait);
            }
            else
            {
               OldActions.Enqueue(a);
            }
         }
      }
   }

In the end I ditched the ThreadWrapper and trying to marshal the event to the UI Thread and used a Task instead, in fact I think I can use task to do most of the stuff in this project so happy days. 最后,我放弃了ThreadWrapper并尝试将事件编组到UI线程,而改用Task,实际上,我认为我可以使用task来完成这个项目中的大部分工作,从而度过快乐的日子。

 Task<bool> t1 = new Task<bool>(() => testBB(ref _bbws_wrapper));
 t1.Start();
 Task cwt1 = t1.ContinueWith(task => { if (t1.Result == true) { this.ssi_bb_conn.BackColor = Color.Green;} else { this.ssi_bb_conn.BackColor = Color.Red; } }, TaskScheduler.FromCurrentSynchronizationContext());


.....
private static bool testBB(ref BBWebserviceWrapper _bbwsw)
    {
        try
        {
            //test the connections
            if (_bbwsw.initialize_v1() == true)
            {
                if (_bbwsw.loginUser("XXXXXXXX", "XXXXXXXXX") == true)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }

        }
        catch
        {
            return false;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM