2013-10-17 47 views
2

我有這樣的問題。例如,我使用mvvm模式動態創建自定義userControl。所以我發佈了一個命令來創建一個userControl。因此,創建看起來像異步/等待wpf應用程序中的方法

private async Task<bool> OnAddUserControl1(List<ALV_VM_ADWERT> control) 
{ 
    try 
    { 
     _cancellationTokenSource = new CancellationTokenSource(); 
     var userControl = _userControlsContainer.CreateUserControl1(control); 

     var task1 = Task.Factory.StartNew(() => 
     { 
      userControl.ViewModel.InOperationEvent += OnUsercontrolInOperationChanged; 
      userControl.ViewModel.ValueTypeChangedEvent += OnValueTypeChanged; 
      userControl.ViewModel.SetExpandableName += OnSetExpandableName; 
     }, _cancellationTokenSource.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext()); 

     var task2 = Task.Factory.StartNew(() => FinalCreatingStep(userControl, control[0].RAUMNAME.Trim()), _cancellationTokenSource.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext()); 
     await Task.WhenAll(task1, task2); 
     return true; 
    } 
    catch (Exception) 
    { 
     return false; 
    }     
} 

和我的問題是 - 它是否意願創建子任務,或者最好有沒有子任務的代碼?如果答案是肯定的,那麼我應該使所有方法異步?如果不是,我不應該做什麼方法異步?

回答

3

它是否會創建子任務,或者最好是沒有子任務的代碼?

這取決於您的要求。如果你的用戶界面長時間被阻塞(凍結),你必須創建一個子任務,否則不會!

如果答案是肯定的,那麼我應該使所有的方法異步嗎?如果不是,我不應該做什麼方法異步?

這裏也取決於你的要求和你的.Net版本。如果您使用的是.NET 4.5,那麼使用Async等待最簡單的方法。如果您使用的是.Net 3.5,而不僅僅是使用Task。如果.Net 2使用BackgorundWorker,則使用Thread類。只有異步方法必須獲得單詞異步。其他方法你不必改變它們。換句話說,只有阻止UI的方法。

4

那些事件訂閱是否真的需要異步?您可能會努力使用異步代碼。

用戶控件構造函數通常是最耗時的部分,必須在UI線程上完成。異步操作通常僅在某種形式的IO或處理被調用時才需要;

  • 讀取文件
  • 寫入文件
  • 處理大型數據集
  • 跨越進程邊界交談的服務器或連接設備

總之,異步任務可能是矯枉過正這裏。

+0

可能是,但我正在使用來自數據庫的信息創建userControl,並且在開始時,它可以是數百個控件或更多。那麼沒有兒童任務的這種方法會更好嗎?對? – Sasha

+0

@Sasha我的建議是將任務檢出數據並將BeginInvoke發送到Dispatcher FOR EACH(這對於調度員正常工作很重要),以控制您想要創建的任務。 – Gusdor

+0

謝謝你的幫助。 – Sasha

2

您目前的代碼沒有任何意義。

UI應用程序中的async代碼的點是響應性 - 即將長時間運行的操作從UI線程移出。正如@Gusdor指出的,async的大多數用例都是基於I/O(或基於事件)的操作,您不想爲了等待某些結果而阻止UI線程。另一個用例是當你有一些CPU綁定工作要做時,但你不想綁定UI線程;在這種情況下,您可以使用Task.Run

但是在你的代碼中,你調用StartNewTaskScheduler.FromCurrentSynchronizationContext,這意味着你的「子」任務將在UI線程上執行。所以你的OnAddUserControl1只是啓動任務將在同一個線程上運行並異步等待它們完成。這是一個非常複雜的無所事事的方式。

雖然我們對StartNew主題,還有一些其他問題:

  1. 代碼是傳遞一個CancellationToken沒有委託過觀察它。
  2. 該代碼指定的AttachedToParent對於兼容await的任務是不正確的。
  3. 如上所述,代碼正在傳遞一個TaskScheduler,它將在UI線程上執行委託。

如果您需要使用後臺(線程池)任務,您應該使用Task.Run instead of Task.Factory.StartNew;我在我的博客上更詳細地介紹。

因此,對於此示例,根本不使用asyncawait

開始使用async是識別I/O密集型(或事件驅動)的部分第一(例如,HTTP請求,數據庫調用),使他們async,然後你的工作方式建立呼叫的最佳方式疊加。