UI被Async / Await阻止

时间:2014-10-21 23:08:21

标签: c# .net events asynchronous async-await

这个问题在这里以多种方式被问到了,但我找不到一个明确的答案,我有一个简单的代码,一个Button,一个Textbox和一个{{1尽管是ButtonClickEventHandler,后者仍保持UI阻塞,代码:

Async

Xaml:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            Task t = new Task(() =>
            {
                for (int i = 0; i < 10000; i++)
                {
                    Dispatcher.Invoke((()=>
                    {
                        TextBox.Text += i.ToString();
                    }));
                }
            });
            t.Start();
            await t;

            //Something else
        }

    }

首先,为什么会发生这种情况? 其次,我应该做些什么来使UI保持正常工作而不会挂起,总是遵循这个逻辑。

2 个答案:

答案 0 :(得分:5)

定义“阻止”。您发布的代码将阻止用户界面。但它肯定会让它真的很忙,这很可能会影响看似就好像被阻挡了一样。就此而言,即使不是真的,也要阻止它用于所有实际目的。

您基本上是在GUI线程上执行拒绝服务攻击。你有一个紧密循环的辅助线程,只是继续在GUI线程上执行东西。不要这样做,事情会好得多。

答案 1 :(得分:5)

正如其他人所说,如果您过于频繁地更新用户界面,最终会阻止用户互动。

就您的代码而言,您应该使用Task.Run而不是任务构造函数,而IProgress<T>代替Dispatcher.Invoke。我有IProgress<T> implementation that handles throttling for you,可以这样使用:

private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
  using (var progress = ObservableProgress<int>.CreateForUi(value => UpdateUi(value)))
  {
    await Task.Run(() => BackgroundOperation(progress));
  }

  ...
}

private static void UpdateUi(int progressUpdate)
{
  TextBox.Text += progressUpdate.ToString();
}

private static void BackgroundOperation(IProgress<int> progress)
{
  for (int i = 0; i < 10000; i++)
  {
    if (progress != null)
      progress.Update(i);
  }
}

不需要人为延误。