2014-09-10 60 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