【问题标题】:Windows 10 UWP StackPanel Visibility not workingWindows 10 UWP StackPanel 可见性不起作用
【发布时间】:2017-05-06 01:33:29
【问题描述】:

我有一个 Windows 10 UWP 应用,在我的 XAML 中,我有一个 StackPanel,用于显示进度条。因此,默认情况下,StackPanel 可见性设置为折叠。然后,在我后面的代码中,我试图在用户单击按钮时将可见性设置为可见,之后,我调用一个方法来进行一些处理。在此示例中,面板永远不会显示。

    private void BtnProcess_OnClick(object sender, RoutedEventArgs e)
    {
        //Set the progress panel to visible
        toggleProgressPanel(true);
        //This is a long running process that can take 3-5 seconds.
        ProcessRequest();
        //Hide the progress panel
        toggleProgressPanel(false);
    }

    private void toggleProgressPanel(bool show)
    {
        pnlProgressBar.Visibility = show ? Visibility.Visible : Visibility.Collapsed;
    }

我在测试期间注意到的一件事是,如果我注释掉 ProcessRequest 调用并且显然隐藏了进度面板,它将在那时显示出来。我还尝试在 ProcessRequest 方法调用中显示和隐藏面板,在方法的最开始显示它并在最后折叠它。

我验证了长时间运行的方法进程实际上需要 3-5 秒才能执行,所以并不是它隐藏面板的速度如此之快以至于你永远看不到它。

这似乎是一个 UI 刷新问题,但我不知道如何解决它。似乎是因为调用方法 BtnProcess_OnClick 正在执行所有操作,直到 BtnProcess_OnClick 方法完成并返回,UI 才真正刷新,这就是它从不显示的原因。那是对的吗?如果是这种情况,你如何解决这个问题?

我不愿意将 ProcessRequest 方法调用放在 Task.Run 中,因为该方法确实需要与 UI 进行大量交互,并且该解决方案会将其放在不同的线程上,这意味着我必须编写大量的代码(我认为)然后解决这个问题。似乎我缺少一个简单的解决方案?

谢谢!

【问题讨论】:

  • ProcessRequest() 应该是异步方法。
  • @Archana 感谢您的回复。所以,如果它是异步的,我仍然可以访问我的所有 UI,因为我在技术上不在另一个线程上,这很好。我没有这样做的原因是因为该方法中没有任何内容是可等待的。据我了解,即使我使方法异步,如果方法内部没有等待,它仍然会运行同步。可以吗,还是我还需要添加一个abritrary await Task.Delay(100);或类似的东西来强制等待?
  • 如果它需要 3-5 秒,那就足够了。现在,您的 UI 会阻塞 3-4 秒,因此您对可见性所做的任何更改都不会反映。

标签: c# .net xaml windows-10-universal


【解决方案1】:

根据 Archana 的建议,我对 ProcessRequest 异步调用了方法。但是,我在该方法中没有任何可等待的内容。因此,只需将方法签名标记为 async 而没有 awaitable 就可以使它仍然同步运行(据我所知)。因此,为了强制它异步运行,我在方法中添加了以下内容并将其标记为异步:

await Task.Delay(50);

这只是一个很小的延迟,几乎不会引起注意,但也给了我一些在方法内部可以等待的东西。

然后,我还更改了此方法的调用者,在我的情况下,按钮按下事件并使其异步,并让它等待对该方法的调用。

现在,它按预期工作,我的 UI 每次都会更新。完整代码如下:

private async void BtnProcess_OnClick(object sender, RoutedEventArgs e)
{
    //Set the progress panel to visible
    toggleProgressPanel(true);
    //This is a long running process that can take 3-5 seconds.
    await ProcessRequest();
    //Hide the progress panel
    toggleProgressPanel(false);
}

private void toggleProgressPanel(bool show)
{
    pnlProgressBar.Visibility = show ? Visibility.Visible : Visibility.Collapsed;
}

private async Task ProcessRequest()
{
    await Task.Delay(50);
    //Now do all of my long running code here
}

执行所有这些操作可以让控制权返回给我的长时间运行方法的调用者,在我的例子中是按钮按下事件,而 ProcessRequest 的长时间运行方法保持异步工作。通过将控制权返回给调用者,它可以完成并允许 UI 更新。

希望这会有所帮助!

【讨论】:

  • 尝试将您的长期任务放入await Task.Run(() => ProcessRequest());,而不是像这样的硬编码延迟。
  • 感谢您的反馈。如果您查看我的 OP 的最后一段,我提到这是一个选项,但我不愿意这样做,因为我调用的 ProcessRequest 方法在 UI 和 UI 控件上做了相当多的工作。 Task.Run 强制该方法在另一个线程上运行,因此每次我想访问 UI 时,我都必须进行重大更改或在方法中添加大量代码,以便与调度程序同步回 UI 线程。除非我错过了什么,否则似乎很痛苦。
猜你喜欢
  • 2019-01-24
  • 2013-06-14
  • 2019-01-03
  • 2016-08-16
  • 2022-07-12
  • 1970-01-01
  • 1970-01-01
  • 2011-07-10
  • 2016-01-24
相关资源
最近更新 更多