C#用户界面更新不是确定性的

C#用户界面更新不是确定性的,c#,uwp,uwp-xaml,C#,Uwp,Uwp Xaml,UWP应用程序,C#,Visual Studio 2017,Windows 10 Creators更新(10.0;构建15063) 让我们将TextBlock1称为T1,将TextBlock2称为T2。。。期望输出为: T1显示“工作已开始” T2显示“步骤1” T2显示“步骤2” T2显示“” T1显示“工作完成” 调试时,实际输出是不确定的: 1:TextBlock更新仅在我进入等待或事件处理程序关闭时发生 2:有时文本块更新发生在await#1,有时发生在await#2,有时同时发生在两个

UWP应用程序,C#,Visual Studio 2017,Windows 10 Creators更新(10.0;构建15063)

让我们将TextBlock1称为T1,将TextBlock2称为T2。。。期望输出为:

T1显示“工作已开始”

T2显示“步骤1”

T2显示“步骤2”

T2显示“”

T1显示“工作完成”

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

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

2:有时文本块更新发生在await#1,有时发生在await#2,有时同时发生在两个位置,有时两者都不发生

3:不管之前的事件如何,T1将显示“工作完成”。T2将在Btn_Click()的末尾显示“”

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

我花了好几天时间在这上面。可能吗

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

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

让我为您详细介绍一下:

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

  • 这是完全正常的。wait调用基本上做了下一件事:启动给定的函数,直到该函数正在进行,才返回被调用方。这还意味着,当等待的函数返回时,作用域立即在等待之后返回到。因此,如果您等待的函数非常快,那么UI可能没有足够的时间应用您的更改

  • 有时文本块更新发生在wait#1,有时发生在wait#2,有时同时发生在两个位置,有时两者都不发生

  • 和上面一样,有时候UI有足够的时间,有时候没有。这就是线的有趣之处。它们是不确定的

  • 不管之前发生了什么,T1都将显示“工作完成”。T2将在Btn_Click()的末尾显示“”

  • DoWork函数完成后,UI重新获得完全控制权,因此它可以应用所有更改->应用最后的文本值

    编辑:


    如果您确实想更新UI,可以
    等待Task.Yield()
    。这将迫使用户界面重新获得控制权。

    让我为您分析一下:

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

  • 这是完全正常的。wait调用基本上做了下一件事:启动给定的函数,直到该函数正在进行,才返回被调用方。这还意味着,当等待的函数返回时,作用域立即在等待之后返回到。因此,如果您等待的函数非常快,那么UI可能没有足够的时间应用您的更改

  • 有时文本块更新发生在wait#1,有时发生在wait#2,有时同时发生在两个位置,有时两者都不发生

  • 和上面一样,有时候UI有足够的时间,有时候没有。这就是线的有趣之处。它们是不确定的

  • 不管之前发生了什么,T1都将显示“工作完成”。T2将在Btn_Click()的末尾显示“”

  • DoWork函数完成后,UI重新获得完全控制权,因此它可以应用所有更改->应用最后的文本值

    编辑:


    如果您确实想更新UI,可以
    等待Task.Yield()
    。这将迫使用户界面重新获得控制权。

    我理解您对希望程序执行所需操作的担忧,但为了实现这一点,您需要了解如何编写只能执行所需操作的代码,然后再编写代码。如果代码做了你不想要的事情,那是因为你写的代码做了你不想要的事情。你是等式中唯一有选择能力的人。“当我请求用户界面更新时,我希望程序执行……”——这听起来像是你在向酒店管理层抱怨。编程不是这样的。
    任务。延迟(1)
    将等待1ms。“你的真实过程真的那么短吗?”埃德普朗科特我不确定我是否理解。我同意我负责编写程序来做我想做的事情。当你“假装做某事”时,这里真正的工作量是多少?它在计算上是有限制的吗?它曾经异步产生过吗?@PaulAbbott不,它们更长了。请记住,一旦请求UI更新,我希望在请求完成之前不会发生任何事情。。。这难道不意味着过程持续时间无关紧要吗?我理解您对希望程序执行您想要的操作的担忧,但为了实现这一点,您需要了解如何编写只能执行您想要的操作的代码,然后再编写代码。如果代码做了你不想要的事情,那是因为你写的代码做了你不想要的事情。你是等式中唯一有选择能力的人。“当我请求用户界面更新时,我希望程序执行……”——这听起来像是你在向酒店管理层抱怨。编程不是这样的。
    任务。延迟(1)
    将等待1ms。“你的真实过程真的那么短吗?”埃德普朗科特我不确定我是否理解。我同意我负责编写程序来做我想做的事情。当你“假装做某事”时,这里真正的工作量是多少?它在计算上是有限制的吗?它曾经异步产生过吗?@PaulAbbott不,它们更长了。请记住,一旦请求UI更新,我希望在请求完成之前不会发生任何事情。。。这不意味着进程持续时间不相关吗?task.yield是use background。它暂时暂停当前函数,并将控制权返回给被调用方。在这种情况下,它将给UI一个更新的机会。当然,这并不能保证任务完成
        private async Task UpdateTextInUI(TextBlock textBlock, string str)
        {
            await textBlock.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                new DispatchedHandler(() => { textBlock.Text = str; }));
        }