C# 用户界面更新不是确定性的 [英] C# user interface updates are not deterministic

查看:26
本文介绍了C# 用户界面更新不是确定性的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UWP 应用程序、C#、Visual Studio 2017、Windows 10 创意者更新(10.0;内部版本 15063).

UWP application, C#, Visual Studio 2017, Windows 10 Creators Update (10.0; Build 15063).

让我们将 TextBlock1 称为 T1,将 TextBlock2 称为 T2...所需的输出是:

Let's call TextBlock1 as T1, TextBlock2 as T2... Desired output is:

T1 显示工作已开始."

T1 shows "Work started."

T2 显示第 1 步"

T2 shows "Step 1"

T2 显示第 2 步"

T2 shows "Step 2"

T2 显示"

T1 显示工作完成".

T1 shows "Work Finished."

    private async void Btn_Click(object sender, RoutedEventArgs e)
    {
        TextBlock1.Text = "Work started.";
        await DoWork();
        TextBlock1.Text = "Work done.";
    }

    private async Task DoWork()
    {
        TextBlock2.Text = "Step 1";
        await Task.Delay(1); //Pretend to do something
        TextBlock2.Text = "Step 2";
        await Task.Delay(1); //Pretend to do something
        TextBlock2.Text = "";
    }

当我调试时,实际输出是不确定的:

When I debug, actual output is non-deterministic:

1:TextBlock 更新在我进入等待或事件处理程序关闭时发生.

1: TextBlock updates only happen when I step into an await or when the event handler closes.

2:有时 TextBlock 更新发生在 await #1,有时发生在 await #2,有时两者都发生,有时两者都不发生.

2: Sometimes TextBlock updates occur at await #1, sometimes at await #2, sometimes at both, and sometimes at neither.

3:无论之前的事件如何,T1 都会显示工作完成".并且 T2 会在 Btn_Click() 的末尾显示 "".

3: Regardless of prior events, T1 will show "Work done." and T2 will show "" at the end of Btn_Click().

当我请求 UI 更新时,我希望程序除了执行更新所必需的之外什么都不做.在 UI 上显示更新之前,它不应继续我的下一个请求.

When I request a UI update, I want the program to do nothing except what's necessary to perform the update. It should not proceed to my next request before the update is shown on the UI.

我在这上面花了几天时间.可能吗?

I've spent days on this. Is it possible?

我找到了一种方法来消除这个问题的非确定性方面.但是我真的不明白发生了什么,它仍然不符合上面粗体的要求:

I've found a way to remove the non-deterministic aspect of this problem. But I don't really understand what's happening, and it still doesn't meet the requirement in bold above:

    private async Task UpdateTextInUI(TextBlock textBlock, string str)
    {
        await textBlock.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            new DispatchedHandler(() => { textBlock.Text = str; }));
    }

推荐答案

让我为你分解:

TextBlock 更新仅在我进入 await 或事件处理程序关闭时发生.

TextBlock updates only happen when I step into an await or when the event handler closes.

这是完全正常的.await 调用基本上做下一件事情:启动给定的函数,直到正在进行返回到被调用者.这也意味着,当您等待的函数返回时,作用域会立即返回到等待之后.因此,如果您等待的功能真的很快,那么 UI 可能没有足够的时间来应用您的更改.

This is perfectly normal. The await call basicly does the next thing: start the given function, and until that is ongoing return to the callee. This also implies, that when your awaited function returns, the scope immideatly returns to after the await. So, if your awaited function is really quick, then the UI might not have enough time to apply your changes.

有时 TextBlock 更新发生在 await #1,有时发生在 await #2,有时两者都发生,有时两者都不发生.

Sometimes TextBlock updates occur at await #1, sometimes at await #2, sometimes at both, and sometimes at neither.

同上,有时UI有足够的时间,有时没有.这就是线程的有趣之处.它们是不确定的.

Same as the above, sometimes the UI has enough time, sometimes it doesn't. That's the funny thing with threads. They are non-deterministic.

无论之前的事件如何,T1 都会显示工作完成".并且 T2 会在 Btn_Click() 的末尾显示 "".

Regardless of prior events, T1 will show "Work done." and T2 will show "" at the end of Btn_Click().

DoWork 功能完成后,UI 重新获得完全控制权,因此它可以应用您的所有更改 -> 应用最后一个 Text 值.

After the DoWork function completes, the UI gains back full control, so it can apply all your changes -> the last Text values get applied.

如果您真的想要更新 UI,您可以await Task.Yield().这将强制用户界面重新获得控制权.

If you really want the UI to update, you can await Task.Yield(). This will force the UI to gain back control.

这篇关于C# 用户界面更新不是确定性的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆