答えてくれてありがとう。私は実際に、少し物議を醸す可能性のある解決策に出くわしましたが、それは少しハックだと解釈する人もいますが、それは私がやりたいことを正確に実行し、それを行う他の方法はないようです。私にとって、これはコード ソリューションであり、ハックではありません。
私は codeproject からダウンロードした WPFBackgroundProgressIndicator オープン ソース プロジェクトを使用しています (私が思うに)。これには、フェードアウトの有無にかかわらずメイン コンテンツにビジー インジケーターを表示するオプション、またはポップアップとして表示するオプションがあり、バックグラウンド スレッドとして実行されます。理想と選んだ理由。
問題は、長時間実行されるメソッドを実行すると、コードの実行は同期的に完了しますが、バインディングの OnPropertyChanged("") の更新はすべて非同期で実行され、Dispatcher スレッドでキューに入れられるため、WPF コントロールが呼び出す機会を得る前に作業メソッドが完了することです。新しい値を取得するための依存関係プロパティのゲッター。あなたがする必要があるのは、すべての Dispatcher イベントが完了するまで効果的に「ブロック」することです. データがまだレンダリングされている間にユーザーが視覚的に何かを実行できるようにしたくないので、完全な更新が完了するまでアプリケーションをブロックしたいので、それが私の要件です。クリーンなブロッキングは、乱雑な相互作用よりも望ましいです。
したがって、解決策は、信じられないかもしれませんが、作業メソッド呼び出しの直後にある 1 行のコードです。以下の通りです。
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);
ご覧のとおり、新しいタスクを Dispatcher スレッドで効果的にキューに入れ、現在のコードの実行をそれが終了するまでブロックしますが、最も低い優先度を与えると、この呼び出しはすべての OTHER ディスパッチャーの実行が終了するまで、つまりすべてのレンダリングが完了するまで待機します。レンダリングが完了すると、この行が実行され、すべてのレンダリングが完了して終了します。コンテキストで使用した完全な方法を以下に示します。このアプローチに関するあなたの考えと議論を歓迎します。
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);
}