谢谢大家的回答。我实际上遇到了一个可能有点争议的解决方案,因为有些人会认为它有点像黑客,但它完全符合我的要求,而且似乎没有其他方法可以做到,所以对我来说,这是一个代码解决方案,而不是一个黑客。
我正在使用我从 codeproject 下载的 WPFBackgroundProgressIndicator 开源项目(我认为),它可以选择在主要内容中显示繁忙指示器,带或不带淡出,或作为弹出窗口,它作为后台线程运行理想以及我为什么选择它。
问题是,当您运行长时间运行的方法时,代码执行同步完成,但所有绑定 OnPropertyChanged("") 更新异步运行并在 Dispatcher 线程上排队,因此您的工作方法在 WPF 控件有机会调用之前完成依赖属性的 Getter,以检索新值。您需要做的是有效地“阻塞”,直到所有 Dispatcher 事件完成,这就是为什么不是每个人都会喜欢这个解决方案,因为它“阻塞”,但这正是我想要做的。我想阻止应用程序直到完全更新完成,因为我不希望用户在数据仍在呈现时能够在视觉上做任何事情,所以这是我的要求。干净的阻塞比混乱的交互更可取。
所以不管你信不信,解决方案是在工作方法调用之后的一行代码。如下。
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);
正如您所看到的那样,它有效地将新任务排队到 Dispatcher 线程并阻止当前代码执行直到它完成,但是当您给它最低优先级时,此调用将等到所有 OTHER Dispatcher 执行完成,即所有渲染完成。渲染完成后,将执行此行,您将在所有渲染完成后退出。我在上下文中使用它的完整方法如下。我欢迎您对这种方法的想法和讨论。
public void LongRunningTaskWithFade(BusyDecorator busy, Action longTask)
{
if (loading) return;
loading = true;
busy.FadeTime = TimeSpan.Zero;
busy.IsBusyIndicatorShowing = true;
// in order for setting the opacity to take effect, you have to delay the task slightly to ensure WPF has time to process the updated visual
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
longTask();
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);
}
finally
{
HideBusyDisplay(busy);
}
}), DispatcherPriority.Background);
}