2010-09-22 59 views
1

由於.NET 4.0有TPL執行異步任務。如果您正在閱讀msdn,則所有與窗體/ UI交互的異步操作仍使用InvokeRequire ... Invoke()模式。 我在問什麼是有原因的?據我所知,TPL應該是舊式線程機制的替代品。那麼在涉及UI線程時忽略它有什麼意義呢? 有關於此的任何想法?TPL與InvokeRequired/Invoke

回答

4

這似乎是相當主觀的...

當你說「由於.NET 4.0」,你說「在今年四月的」 - .NET已經存在了10年,現在,InvokeRequired/Invoke已用於過去的9.爲什麼MS會因任何原因中斷所有現有的UI代碼?即使存在一種調用線程的新方式,它們也不能簡單地修改該模式而沒有巨大的兼容性問題。

此外,TPL與InvokeRequired/Invoke不類似--TPL是關於簡單並行性的,並且調用是關於在特定線程上運行代碼。我不確定爲什麼要替換另一個,即使沒有兼容性問題。

請注意,沒有什麼停止您不使用TPL來確保您在正確的線程上調用UI組件。事實上,你可以輕鬆地做到這一點。但這取決於你,目前的API不會以不向後兼容的方式改變。

1

這裏有什麼問題? TPL的存在不會改變UI本質上是單線程的事實,並且只需要在UI線程上訪問控件。 (這是Windows的限制,而不是.NET UI框架的限制,TPL不能改變數十年的Windows設計限制)。

如果你的問題是關於混合任務和InvokeRequired/Invoke,還有更多的TPL以調用爲導向的方式。 TPL提供了一個內置的方法來安排繼續任務在UI線程上運行。因此,您將面向後臺的工作放在一個Task中,然後在另一個Task中更新您的UI。請參閱this post on task schedulers and SynchronizationContext

(不過說真的,TPL不替代任何舊線程的API。如果調用是做你想要做的,用什麼樣的最佳方式。)

0
private void WorkProcessingAsync(IWorkItem workItem) 
{ 
    IsBusy = true; 
    /* ============================= 
    * Create a TPL Task and pass the current UiCulture in an state Object to resolve the correct .resx file for translation/globalisation/Multilanguate features in Background Thread 
    * ==============================*/ 
    Task<IWorkItem> task = Task.Factory.StartNew((stateObj) => 
    { 
     // here we are already in the task background thread 
     // save cast the given stateObj 
     var tuple = stateObj as Tuple<IWorkItem, CultureInfo>; 

     Debug.Assert(tuple != null, "tuple != null"); 

     Thread.CurrentThread.CurrentUICulture = tuple.Item2; // Here we set the UI-Thread Culture to the Background Thread 

     var longRunningOperationAnswer = LongRunningOperation.DoLongWork(tuple.Item1); 
     return longRunningOperationAnswer; 

    }, new Tuple<IWorkItem, CultureInfo>(workItem, Thread.CurrentThread.CurrentUICulture)); // here we pass the UI-Thread Culture to the State Object 



    /* ======================================================================= 
    * Handle OnlyOnRanToCompletion Task and process longRunningOperationAnswer back in UiThread 
    * =======================================================================*/ 
    task.ContinueWith((t) => 
    { 
     IsBusy = false; 
     // handle longRunningOperationAnswer here in t.Result 
     Log.Debug("Operation completet with {0}", t.Result); 

    }, CancellationToken.None 
    , TaskContinuationOptions.OnlyOnRanToCompletion 
    , TaskScheduler.FromCurrentSynchronizationContext()); 

    /* ======================================================================= 
    * Handle OnlyOnFaulted Task back in UiThread 
    * =======================================================================*/ 
    task.ContinueWith((t) => 
    { 
     IsBusy = false; 
     AggregateException aggEx = t.Exception; 

     if (aggEx != null) 
     { 
      aggEx.Flatten(); 
      Log.ErrorFormat("The Task exited with Exception(s) \n{0}", aggEx); 
      foreach (Exception ex in aggEx.InnerExceptions) 
      { 
       if (ex is SpecialExaption) 
       { 
        //Handle Ex here 
        return; 
       } 
       if (ex is CustomExeption) 
       { 
        //Handle Ex here 
        return; 
       } 
      } 
     } 
    }, CancellationToken.None 
    , TaskContinuationOptions.OnlyOnFaulted 
    , TaskScheduler.FromCurrentSynchronizationContext()); 
}