等待async顺利写入ui但仍然冻结它

时间:2014-04-14 15:00:00

标签: c# wpf async-await

我正在做翻译。 UI是WPF应用程序。单击按钮,我启动一个必须写入ui的长任务。过去,我和背景工作者做过类似的事情。我意识到后台工作者已经过时了,异步是要走的路(更少噪音和更清洁等)。

我有一项漫长的任务,即在循环时顺利地将文字写入屏幕,但屏幕仍然“冻结”,即无法点击按钮等。

如果我在task.run结束时添加30毫秒的睡眠,则ui会响应并且我的对象事件正在运行。但睡眠似乎比30毫秒慢得多。

private void AnalyzeButton_Click( object sender, RoutedEventArgs e )
{
    var flowManager = new InterpreterFlowManager(){ ... }
    flowManager.Initialize();
    flowManager.ContinueFlow();
}
....

public class InterpreterFlowManager
{
    async public void ContinueFlow()
    {
        string LineBuffer = "";

        string lastTextBlockString = "";
        while (...)
        {
            lastTextBlockString = "";
            bool endLoop = false;

            await Task.Run(() => 
            {
                if (...)
                {
                    ...
                    if (...)
                    {
                        switch (...)
                        {
                            case x:
                                lastTextBlockString = "\r\nEntrer un nombre :";
                                endLoop = true;
                                break;
                            case y:
                                lastTextBlockString = "\r\n" + ConsoleInfo.Message;
                                break;
                        }
                    }
                }
                else
                    LineIndex++;

                          *********************************
                           SMALL SLEEP HERE MAKE UI RESPONSIVE.
                          ************************************
            });

            //ACCESS TO A UI TEXTBOX
            var lastTextBlock = (InteractiveWindow.Children.Cast<TextBox>().Where(c => c.GetType() == typeof(TextBox) && c.IsReadOnly)).Last();
            //SUCESSFULLY APPEND
            lastTextBlock.Text += lastTextBlockString;
            Output.Text += _tmpResultString + "\r\n";

            _tmpResultString.Clear();

            if (endLoop) 
            {
                TextBox input = new TextBox();
                input.BorderBrush = Brushes.DarkRed;
                input.KeyUp += input_KeyUp; // further stuff

                InteractiveWindow.Children.Add(input);
                return; 
            }
        }
    }
}

1 个答案:

答案 0 :(得分:3)

如果您熟悉BackgroundWorker,那么async世界就会有一个非常直接的翻译:

  1. 使用单个BackgroundWorker电话替换每个Task.Run个实例。
  2. ProgressChanged事件处理程序替换为Progress<T> (described on MSDN)
  3. RunWorkerCompleted事件替换为await Task.Run(...)
  4. 之后的代码

    您的代码看起来像是在Task.Run循环中开始单独的while。如果每个Task.Run中的代码执行得非常快,那么这将不会让您的UI有机会做出响应。考虑移动while代理中的Task.Run循环并使用IProgress<T> / Progress<T>进行更新。