我正在修复一个已经存在的应用程序,我遇到了一些奇怪的问题。
在GUI的某些部分,我们的操作需要一些时间。因此,我们创建了一个名为Wait
的小窗口,其中包含一条简单的消息Please wait...
。我们只需在需要时Show/Hide
窗口。
但这是问题所在。我们第二次显示该窗口时,不会显示Please wait...
Label
in。
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>
Wait.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
但没有效果的事情。
不仅仅是如何解决这个问题的答案,我想明白为什么会这样?
答案 0 :(得分:1)
正如Hans Passant发布的那样,你应该在除UI线程之外的单独线程上进行长时间的运行。如果你真的坚持在主线程上执行此操作,那么通常会调用Application.DoEvents()
之类的东西。这个调用在WPF中不存在,因为它是一种黑客攻击,并且表明你在UI线程上做了太多工作。但是,如果您真的 必须 尝试关闭它,您可以在第二次显示窗口后立即添加此行:
Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
它与Application.DoEvents()
基本相同,只有一些小怪癖。然而,更好的解决方案是启动BackgroundWorker
来执行长时间运行的过程,同时UI保持活动状态。更多信息here。
答案 1 :(得分:0)
正如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线程。