4

UIディスパッチャーでダイアログを呼び出そうとしています:

class DialogService : IDialogService
{
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher;

    public bool? Show(IDialogViewModel viewModel)
    {
        if (_dispatcher.CheckAccess())
        {
            var dialogWindow = new DialogWindow();
            return dialogWindow.Show(viewModel);
        }
        else
        {
            Func<IDialogViewModel, bool?> func = Show;
            return (bool?)_dispatcher.Invoke(func, viewModel);
        }
    }
}

ただし、呼び出しはInvoke永久にブロックShowされ、UI スレッドで呼び出されることはありません...

使用BeginInvokeはオプションではありません: リモート オブジェクトからのイベントを処理しているため (.NET リモート処理を使用)、すぐに結果が必要です。

何か案が ?


アップデート

問題のより完全な説明は次のとおりです。

.NET Remoting を使用して Windows サービスと通信するクライアント アプリケーションがあります。ある時点で、クライアントは操作を実行するためにサービスを呼び出します (この呼び出しは、ユーザー アクション (この場合はボタンのクリック) によってトリガーされます)。サービスは、操作を実行するために資格情報を必要とする場合があります。その場合、CredentialsNeededクライアントによって処理されるイベントが発生します。次に、クライアントはダイアログを表示してユーザーに資格情報の入力を求め、イベントの引数に適切なプロパティを設定します。イベント ハンドラーが戻ると、サービスは資格情報を使用して操作を完了し、制御をクライアントに返します。

そのため、イベントを受信すると、UI スレッドはサービス側で操作が完了するのを待っています...呼び出しが処理されない理由だとInvoke思いますが、どうすれば回避できますか? ダイアログを表示する別のUI スレッドを作成できますか? WinForms では、別のメッセージ ポンプを で開始できることApplication.Runはわかっていますが、WPF で同じことを行う方法がわかりません...

4

3 に答える 3

4

このメソッドの呼び出し中に、UI スレッドの別のメソッドが取得しようとしているロックを所有していますか? それは確かにそれを説明するでしょう。

これは毎回起こりますか?これにより、診断が容易になることは間違いありません。

私にとっては珍しいことですが、デバッガーに行くことをお勧めします。ブレークを押して、スレッドが何をしているかを確認してください。

最後に、結果が必要であることはわかっていますが、代わりに呼び出す(そしてダミーの値を返す) とどうなりますか? BeginInvokeそれはディスパッチャでメソッドを呼び出しますか? 明らかに、これは長期的な修正にはなりませんが、より多くの診断情報が得られます。

于 2010-06-22T16:57:38.200 に答える
2

私は最終的に私の問題の解決策を見つけました。独自のディスパッチャーを使用して、新しいスレッドでダイアログを表示するだけです。変更されたコードは次のとおりです。

class DialogService : IDialogService
{
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher;

    public bool? Show(IDialogViewModel viewModel)
    {
        if (_dispatcher.CheckAccess())
        {
            DoShow(viewModel);
        }
        else
        {
            bool? r = null;
            Thread thread = new Thread(() => r = DoShow(viewModel));
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
            return r;
        }
    }

    private static bool? DoShow(IDialogViewModel viewModel)
    {
        var dialogWindow = new DialogWindow();
        return dialogWindow.Show(viewModel);
    }
}
于 2010-06-23T09:39:32.113 に答える
1

Invoke を使用しようとしているときに、UI スレッドが別のもの (おそらくバックグラウンド スレッド) への呼び出しをブロックしていませんか? もしそうなら、あなたの手には古典的な行き詰まりがあります。2 つのスレッドがそれぞれ他方の戻りを待機しています。

Windows フォームでは、デッドロックを回避するために、多くの場合、バックグラウンドで多くの「メッセージ ポンピング」を実行しますが、多くの場合、予期しない再入可能性により、さらに多くの問題が発生し、バグを見つけるのが困難になります。

UI スレッドがブロッキング呼び出しを行っていないと思われる場合は、アプリケーションをデバッガーで実行し、デッドロックが発生したときにデバッガーを中断する必要があります。次に、[スレッド] ウィンドウでメイン スレッドを探します。メイン スレッドをダブルクリックし、[コール スタック] ウィンドウを見て、メイン スレッドがどこにあるかを確認します。

Send の DispatcherPriority を明示的に指定することもできますが、真のデッドロックがある場合は問題にならないと思います。

于 2010-06-22T16:58:50.037 に答える