2014-05-12 50 views
0

我有一个按钮,当我点击它,我希望它与价值异步与标签文本

这是我的按钮

 private async void Button_Click(object sender, RoutedEventArgs e) 
     { 
     await DoItAsync(); 
     } 

,这是DOIT更新UI!

public async Task DoSomethingAsync() 
    { 
     await Task.Run(()=>{ 
      for(int i = 0; i < 2000; i++) 
      { 
       //labelName.Content = i.ToString(); 
       Console.WriteLine(i); 
      } 

     }); 
    } 

,所以如果我运行上面的代码,请点击我的按钮,DoItAysnc被调用,所有的号码都显示在控制台中。

如果我未评论

labelName.Content = i.ToString(); 

我得到一个异常,事实上如下:因为不同的线程拥有它调用线程不能访问该对象。

我知道异步并等待不解决线程为你,但我确实认为这会工作。我想知道如何让这个工作,以便在每个i值都更新UI而不会导致UI无响应。

对此的任何好资源也会有帮助。

与往常一样,各种关于

+0

这是什么? WPF,WinForms,Windows运行时? – Smeegs

+0

欢迎来到UI线程世界。对于WPF学习Dispatcher,对于Winforms学习Invoke。 –

+2

您需要为异步/等待做实际工作才有用。请显示你实际正在做的事情而不是一个人为的例子,在你当前的代码示例中有0个理由使用async/await或线程。 –

回答

8

在这种特殊情况下,似乎所有你正在做的基本上是计算到2000年的标签一样快,你所能。这不太可能是您的实际用例。

如果你想被更新多个不同的异步操作的UI(其中该操作,例如,只是在等待一段时间),那么你可以组织你的代码如下所示:

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    for (int i = 0; i < 2000; i++) 
    { 
     await Task.Delay(TimeSpan.FromSeconds(1)); 
     labelName.Content = i.ToString(); 
    } 
} 

如果你正在做的概念被更新与长时间运行的非UI操作的进度的UI,那么Progress类被设计来专门处理是:

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Progress<int> progress = new Progress<int>(
     i => labelName.Content = i.ToString()); 
    await Task.Run(() => DoWork(progress)); 
} 
private void DoWork(IProgress<int> progress) 
{ 
    for (int i = 0; i < 2000; i++) 
    { 
     //Do Stuff 
     progress.Report(i); 
    } 
} 

国内首个普遍的选择是有道理的,如果你C将您的问题分解为一组小的异步操作,其中UI在每个操作之间更新。如果有一个长的非UI操作不能轻易分解为更小的操作,则可以采用第二种方法。

0

看看答案here。无论您如何启动工作线程(Thread.Start,Task.Run,​​BackgroundWorker.RunWorkerAsync),除非在UI线程上运行,否则不会影响UI的更改。

正如@ t-mckeown指出的,解决方案是强制你的方式进入UI线程。你如何做到这一点取决于技术(WFP = Dispatcher,WinForms = InvokeRequired/BeginInvoke)。

+0

'await'捕获当前同步上下文和marshals回调到该上下文,从而防止开发人员需要显式编组到UI线程。开始使用这种编程风格是巨大的优势。 – Servy