【问题标题】:await async write smoothly to ui but still freeze itawait async 顺利写入 ui 但仍冻结它
【发布时间】:2014-04-23 05:52:50
【问题描述】:

我正在做口译员。 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; 
            }
        }
    }
}

【问题讨论】:

    标签: c# wpf async-await


    【解决方案1】:

    如果您熟悉 BackgroundWorker,那么可以很直接地转换为 async 世界:

    1. 将每个 BackgroundWorker 实例替换为单个 Task.Run 调用。
    2. 将ProgressChanged 事件处理程序替换为Progress&lt;T&gt; (described on MSDN)。
    3. 用await Task.Run(...)之后的代码替换RunWorkerCompleted事件。

    您的代码看起来像是在 while 循环中启动了一个单独的 Task.Run。如果每个Task.Run 中的代码执行得非常快,那么这不会让您的 UI 有机会做出响应。考虑在Task.Run 委托中移动while 循环,并使用IProgress&lt;T&gt;/Progress&lt;T&gt; 进行进度更新。

    【讨论】:

    • 该任务最多需要 10 秒才能运行。你还是建议走进步路线吗?嗯,好吧,在那 10 秒内,循环完成了大约 100 次。
    • 如果任务(而不是整个 while 循环)需要 10 秒,那么您的 UI 肯定应该是响应式的。尝试创建并发布一个最小的复制品。
    • 是的,10秒是整个while循环,大概循环了100次
    • 如果每个 Task.Run 的执行时间为 100 毫秒,那么对于响应式 UI 来说已经足够了。看看你能做些什么来创建一个最小的复制;我们可以运行并观察其行为的东西。
    • 好的,所以当长任务运行时,我发现如果我在任务运行的整个过程中非常快速地点击一些东西,一些点击会成功完成,但有延迟。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 2016-06-13
    • 1970-01-01
    • 2016-02-13
    • 2014-01-04
    • 1970-01-01
    相关资源
    最近更新 更多