0

我看到的所有使用 SynchronisationContext.Post 的示例都在同一个类中使用过。我所拥有的是 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)
           {

           }

事件似乎在没有任何错误的情况下触发,但在 uiThread 上没有收到任何内容 - 我不确定我对子 updateConnStatus 的签名是否正确,或者它是否像这样工作。我显然希望在 uithread 上处理该事件并更新该子的标签。

在以前的 vb.net 项目中,我曾经直接在线程上引用表单并使用委托来调用回调,但显然这是一个糟糕的设计,因为我正在混合应用程序层。我想使用同步上下文,因为它是线程安全的,但我见过的大多数示例都使用了调用。

有什么我想念的想法吗?谢谢

4

2 回答 2

1

我写了这个对我有用的助手类。在应用程序启动的某个地方在 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);
            }
         }
      }
   }
于 2012-08-20T12:20:06.607 回答
0

最后我放弃了 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;
        }
    }
于 2012-08-20T20:24:16.030 回答