我试图为一个长时间运行的操作显示一个请等待对话框。问题是因为这是单线程的,即使我告诉等待屏幕显示它也不会显示。有没有办法可以改变屏幕的可见性并使它立即显示?我包括了Cursor调用作为一个例子。在我调用这个。Cursor之后,光标立即更新。这正是我想要的行为。
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Cursor = System.Windows.Input.Cursors.Pen;
WaitScreen.Visibility = Visibility.Visible;
// Do something long here
for (Int32 i = 0; i < 100000000; i++)
{
String s = i.ToString();
}
WaitScreen.Visibility = Visibility.Collapsed;
this.Cursor = System.Windows.Input.Cursors.Arrow;
}
WaitScreen只是一个Z索引为99的网格,我可以隐藏和显示它。
我真的不想使用一个后台工作者,除非我不得不这样做。在代码中有很多地方会发生这种启动和停止。
5条答案
按热度按时间7cwmlq891#
在单线程环境下运行真的会很痛苦,而且它永远不会像你希望的那样工作。在WPF中,窗口最终会变黑,程序会变成“没有响应”。
我建议使用BackgroundWorker来完成您的长时间运行任务。
没那么复杂,这样就行了.
然后,您可以查看ProgressChanged事件以显示进度(请记住将WorkerReportsProgress设置为true)。如果DoWork方法需要对象(在e.Argument中提供),还可以向RunWorkerAsync传递参数。
这确实是最简单的方法,而不是尝试单线程化。
xghobddn2#
我找到办法了!多亏了this thread。
这个函数需要在长时间运行的操作之前被调用,这将强制UI线程更新。
laximzn53#
看看我对这个微妙主题的全面研究吧。如果你无法提高实际性能,你可以选择以下方法来显示等待消息:
选项#1执行一段代码,以与执行真实的任务相同的方法同步显示等待消息。只需将这一行放在一个冗长的过程之前:
它将在 Invoke() 结束时处理主调度器线程上的挂起消息。
选项#2显示“等待”屏幕并更新UI(处理未决消息)。
为了做到这一点,WinForms 开发人员执行了Application.DoEvents方法。WPF提供了两种替代方法来实现类似的结果:
选项#2.1使用DispatcherFrame class时。
检查MSDN中的一个有点庞大的示例:
选项#2.2调用空操作
参见讨论,哪一个(2.1或2.2)更好here。恕我直言,选项#1仍然优于#2。
选项#3在单独的窗口中显示等待消息。
当你显示的不是一个简单的等待消息,而是一个动画的时候,它就派上用场了。在我们等待另一个长时间渲染操作完成的同时,渲染一个正在加载的动画是一个问题。基本上,我们需要两个渲染线程。你不能在一个窗口中有多个渲染线程。但是你可以把你的加载动画放在一个新的窗口中,它有自己的渲染线程,使它看起来不是一个单独的窗口。
从this github下载 * WpfLoadingOverlay.zip *(它是文章“*WPF响应性:渲染过程中异步加载动画 *",但我在网上找不到了)或者看看下面的主要思想:
bis0qfac4#
另一种选择是将长时间运行的例程编写为一个函数,该函数返回
IEnumerable<double>
以指示进度,并且只需说:例如,这将指示30%的进程,然后您可以使用WPF计时器在“后台”作为协作协程来执行它。
It's described in some detail here, with sample code.
njthzxwz5#
简短回答
简化前面的答案,您可以只创建一个类似这样的任务,只需对代码进行非常小的更改。
可扩展的答案
如果你想让它更具伸缩性,你可以创建一个
RunLongTask(Action action)
方法:在这里你可以把
IsBusy
绑定到你的窗口控件属性上,比如IsEnabled
或者Visibility
属性(为了可见性,你需要一个转换器,我会在答案的最后添加)然后,您可以这样使用它:
或
使用的转换器