标签在第二个窗口后未显示
本文关键字:显示 窗口 第二个 标签 | 更新日期: 2023-09-27 18:31:02
我正在修复一个已经存在的应用程序,但我遇到了一些奇怪的问题。
在 GUI 的某些部分,我们的操作需要一些时间。因此,我们创建了一个名为 Wait
的小窗口,其中包含一个简单的消息Please wait...
。我们只需在需要时Show/Hide
窗口。
但问题来了。第二次显示窗口时,不显示Please wait...
Label
。
Wait.xaml:
<Window x:Class="WpfApplication1.Wait"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Wait" SizeToContent="WidthAndHeight">
<StackPanel>
<Label>Please wait...</Label>
</StackPanel>
</Window>
等待.xaml.cs
public partial class Wait : Window
{
public Wait()
{
InitializeComponent();
}
}
最后,我只是在最小的WPF应用程序中尝试一下:
// The window is shown perfectly
m_WaitWindow.Show();
Thread.Sleep(5000);
m_WaitWindow.Hide();
Thread.Sleep(2000);
// The label is not shown, the window is empty
m_WaitWindow.Show();
Thread.Sleep(5000);
m_WaitWindow.Hide();
我不知道如何解决这个问题,我尝试了很多事情,比如UpdateLayout
Show
后都没有效果。
不仅仅是关于如何解决这个问题的答案,我会理解为什么会发生这种情况?
正如 Hans Passant 发布的那样,您应该在 UI 线程以外的单独线程上执行长时间运行的工作。 如果你真的坚持在主线程上这样做,那么通常的做法是调用类似 Application.DoEvents()
的东西。 此调用在 WPF 中不存在,因为它是一种黑客攻击,表明您在 UI 线程上做了太多工作。 但是,如果您真的必须尝试完成此操作,则可以在第二次显示窗口后立即添加此行:
Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
它本质上与Application.DoEvents()
相同,只是有一些小怪癖。 但是,更好的解决方案是启动一个BackgroundWorker
来执行长时间运行的过程,同时 UI 保持活动状态。 更多信息在这里。
正如Hans Passant所说,你正在阻止UI线程。 (不打算像苏斯博士那样回答...
通过在后台线程中进行等待/繁重的工作,这很容易解决。 您的最终实现可能会因您使用的 .NET 和 Visual Studio 版本而异,但您可以通过以下简单示例完成您所追求的目标:
// The window is shown perfectly.
m_WaitWindow.Show();
ThreadPool.QueueUserWorkItem(arg =>
{
Thread.Sleep(5000);
Dispatcher.BeginInvoke(new Action(() => m_WaitWindow.Hide()));
Thread.Sleep(2000);
// The window is still shown perfectly, because the UI thread is not being blocked.
Dispatcher.BeginInvoke(new Action(() => m_WaitWindow.Show()));
Thread.Sleep(5000);
Dispatcher.BeginInvoke(new Action(() => m_WaitWindow.Hide()));
}, null);
注意:在原始情况下,您还应该看到弹出窗口对用户交互没有响应 - 这是一个好兆头,表明您已经阻止了 UI 线程。