与标签文本异步

时间:2014-05-12 15:17:56

标签: c# .net user-interface async-await

我有一个按钮,当我点击它时,我希望它用值

更新UI

这是我的按钮

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

这是DoIt!

    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(); 

我得到一个例外,事实如下:调用线程无法访问此对象,因为另一个线程拥有它。

我知道Async并等待不为你解决线程问题,但我确实认为这会有效。我想知道如何使其工作,以便为每个i值更新UI,而不会使UI无响应。

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

一如既往,种类问候

2 个答案:

答案 0 :(得分: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);
    }
}

通常,如果您可以将问题分解为一组小的异步操作,其中UI在每个操作之间更新,则第一个选项是有意义的。如果有一个长的非UI操作无法轻易分解为较小的操作,则完成第二种方法。

答案 1 :(得分:0)

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

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

相关问题