2014-09-10 66 views
0

我知道我錯過了一些愚蠢的東西,「StartProcess」方法導致用戶界面無響應,沒有任何數量的谷歌搜索和教程讓我得到答案。WPF異步任務鎖定用戶界面

這裏是我的代碼:

public MainWindow() 
    { 
     InitializeComponent(); 
     txtBlock.Text = "Testing"; 
     Initialize(); 
    } 

    public void Initialize() 
    { 
     uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

     StartProcess(); 
    } 

    async void StartProcess() 
    { 
     Task<int> result = Task.Factory.StartNew(() => 
     { 
      txtBlock.Text += ("\n starting updater"); 
      while (true) 
      { 
       Thread.Sleep(3000); 
      } 
      return 0; 
     }, CancellationToken.None, TaskCreationOptions.LongRunning, uiScheduler); 
    } 

一些背景:我建立有輪詢DB每5分鐘和一個待辦事項列表供用戶更新用戶界面的應用程序,因此而(真)循環。應用程序必須在其整個生命週期內不斷調查數據庫。

+0

你可以嘗試使用'取代'Thread.Sleep' Task.Delay'。目前,您似乎在UI線程上調用了「Thread.Sleep」,這會使您的UI無響應。此外,簡單地讓你的方法'異步'不會執行魔術。 – 2014-09-10 15:17:20

+0

你應該看看[Rx](http://stackoverflow.com/tags/system.reactive/info「system.reactive」)。 – 2014-09-10 16:08:00

回答

6

那麼,你問TPL在UI線程中調用Func,它遵從你的話。

在Start中您將uiScheduler作爲TaskScheduler通過,因此任務將排隊到Dispatcher,這將由UI線程調用。

如果你不想在UI線程中執行,那麼使用TaskScheduler.Default,這樣你就不能在Func裏面更新txtBlock.Text。您需要編組調用UI線程,或者在StartNew之前設置txtBlock.Text以外的Func

如果您使用.Net 4.5,請始終選擇Task.Run,注意StartNew is dangerous

幾件事情需要注意:

  • 請注意,你不借力async功能都沒有。如果沒有 和await關鍵字方法根本不是異步的。您根本不需要使用 async關鍵字(實際上,您將收到編譯器警告,請注意編譯器說的 注意事項)。
  • 避免使用異步無效方法(除了事件處理程序),如果不需要任何返回值,則始終使用async Task,以便您可以在調用方中等待它或附加延續等等。

更新添加一些代碼:

async Task StartProcess() 
{ 
    while (true) 
    { 
     var result = await Task.Run(()=> MethodWhichCallsDBAndReturnsSomething()); 
     txtBlock.Text = result.ToString();//Use result and update UI 
     await Task.Delay(5 * 60 * 1000);//await 5 mins 
    } 
} 
+0

關於你的最後一行 - 他們然後需要編組任何調用來更新UI返回到UI線程(你毫無疑問知道,但也許OP不)。 – 2014-09-10 15:20:51

+0

@DanielKelley我正在更新我的答案。你太快:) – 2014-09-10 15:22:26

+0

謝謝sriram,非常豐富。我會如何將這個await關鍵字合併到假設永久運行的任務中?我的目標是啓動一個工作線程,該線程將每隔5分鐘繼續輪詢數據庫,並在返回相關數據時更新ui。 – Swifty 2014-09-10 21:35:24