2011-05-11 66 views
3

在我的ViewModel我有這樣的代碼:爲什麼我的UI在使用System.Threading.Task類的時候被阻塞?

Logs = new ObservableCollection<Log>(); 
Logs = Task.Factory.StartNew(() => mainModel.GetLogs()).Result; 

wtih日誌是一個非常簡單的類與一對夫婦的公共屬性。

根據我對Task類的理解,以這種方式調用的mainModel函數GetLogs()應該在單獨的線程上運行,並且它從數據庫中提取記錄時我的UI應該是響應式的,但這不是發生的情況,而是當記錄正在從數據存儲中提取時,我的用戶界面被阻止。

我希望有人能解釋爲什麼...... TIA。

編輯:我的任務類的understading不全,使用任務類的ContinueWith方法將確保異步執行作爲成員回覆說明如下......

回答

4

這是因爲你叫Result你開始之後異步操作。 Result屬性的獲取器會阻止當前線程的執行,直到任務完成。

更新:

爲了得到結果異步,你需要調用ContinueWith並指定當任務完成後,將被調用的函數:

Task.Factory.StartNew(() => mainModel.GetLogs()).ContinueWith(t => Logs = t.Result); 
+0

換句話說,我應該先創建Task對象,然後在下一行代碼上調用StartNew並最後在下一行調用taskName.Result? – 2011-05-11 18:44:48

+0

@kzen - 查看我的更新。 – 2011-05-11 18:52:49

+0

謝謝,就是這樣......我對Task類的理解顯然並不完整,這並不奇怪,因爲我今天開始學習它:) – 2011-05-11 19:01:51

2

,則不應使用結果屬性是這樣的我認爲,from MSDN

此屬性的get訪問器確保th在異步操作完成之前完成返回。一旦計算結果可用,它就會被存儲起來,並在稍後調用Result時立即返回。

它使當前線程等待,如果您在任務運行時訪問它。

+0

那麼如何在不阻塞UI線程的情況下獲得Task的結果呢? – 2011-05-11 18:52:33

+1

您可以將任務封裝在任務本身中(這是有問題的,因爲它違背了「結果」的要求),或者您可以像Pavlo Glazkov所說的那樣使用'ContinueWith'來完成任務。 – 2011-05-11 18:57:43

1

假設mainModel.GetLogs是線程安全的,你可能需要這樣的東西,它在後臺線程上調用GetLogs,然後只在結果獲取日誌時將日誌設置爲結果。 TaskScheduler.FromCurrentSynchronizationContext()確保該部分的執行在UI線程上運行,如果您的UI綁定到該集合,那麼將需要該部分。

Task doStuff = Task.Factory.StartNew<ICollection>(() => 
    { 
     return mainModel.GetLogs(); 
    }) 
    .ContinueWith((result) => 
    { 
     Logs = result; 
    }, TaskScheduler.FromCurrentSynchronizationContext()); 
相關問題