感謝所有的答案。我實際上遇到了一個可能有點爭議的解決方案,因爲有些人會認爲這有點破解,但它確實是我想要的,而且似乎沒有其他辦法可以做到這一點,所以對我來說這是一個代碼解決方案,而不是黑客。我使用WPFBackgroundProgressIndicator開源項目,我從代碼項目(我認爲)下載,它可以選擇顯示主內容中的忙指示符有或沒有淡出,或作爲彈出窗口,它作爲後臺線程這是理想的,爲什麼我選擇它。
問題是,當您運行長時間運行的方法時,代碼執行會同步完成,但所有綁定OnPropertyChanged(「」)更新都會異步運行並在Dispatcher線程上排隊,因此您的工作方法在WPF控件之前完成有機會調用依賴屬性的Getters來檢索新值。你需要做的是有效地「阻止」,直到所有Dispatcher事件完成,這就是爲什麼不是每個人都會喜歡這個解決方案,因爲它「阻止」,但那正是我想要做的。我想阻止應用程序,直到完整更新完成爲止,因爲我不希望用戶能夠在數據仍在渲染時進行任何可視化操作,所以這是我的要求。清理阻塞比混亂的交互更可取。
因此,解決辦法,無論你相信與否,只是工作方法調用之後的一行代碼。它如下。
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);
正如你可以有效地看到排隊調度線程,直到它完成塊當前的代碼執行上一個新的任務,但是當你給它的優先級最低,這個調用會等到所有其他的調度執行完畢,即所有渲染完成。渲染完成後,該行將被執行,您將退出所有渲染完成。下面是我在上下文中使用的完整方法。我歡迎您對這種方法進行思考和討論。
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);
}
你嘗試調用NotifyPropertyChanged方法,當你長時間運行的方法完成的工作? – Legoless
長時間運行的方法會經歷並更新很多ViewModel對象,很多屬性。在我調用OnPropertyChanged()的每個屬性的Setter中,這些都是在長時間運行的方法完成之前調用的,因爲它們是其中的一部分。這是你的意思嗎?我不確定INotifyPropertyChanged的內部工作原理,但是基於觀察到的行爲,我猜測INotifyPropertyChanged將調用發送到GUI調度程序線程,該線程隨後與所有後續的線程一起排隊,直到長時間運行的工作完成並且GUI線程釋放? – NZJames
你正在執行長時間運行的任務嗎?在一個單獨的線程,後臺工作人員等?你可以發佈一些代碼嗎? –