1

通常の Windows.MessageBox の代わりに使用したい WPF ウィンドウがあります。主に、エラーの内容を表示する「詳細」ボックスが必要なためです。スレッド化を開始するまで、これは正常に機能します。

たとえば、少し時間がかかる SQL Server データベースのテーブルのリストを取得するタスクを実行したいと考えています。エラーが発生した場合 (接続しようとするとタイムアウトになるなど)、カスタム ポップアップに例外の詳細を表示したいと考えています。

最初はクラッシュし続けます。少し読んだ後(SOで皆さんに)、タスクがUIスレッドになく、ウィンドウを表示できないことに気付きました(ネイティブのMessageBoxはまだ機能しているようです)。それで、私は次のことを思いつきました:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        Task t = Task.Factory.StartNew(() => DoWork());
    }

    void DoWork()
    {
        Thread thread = new Thread(() =>
        {
            Window1 popup = new Window1();
            popup.Show();
            System.Windows.Threading.Dispatcher.Run();
        });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }
}

これは、私が行っていることの基本を示すことができるように作成した一時的なアプリです。メイン アプリでは、例外を引数としてポップアップ ウィンドウに送信しています。

私の質問はこれです:これはこれを行うための最良の方法ですか? 正常に動作しているように見えますが、このようなスレッドを混在させることがベスト プラクティスであると 100% 確信していたわけではなく、それを公開しようと考えました。

それが良い解決策である場合、次の質問は、ポップアップを親ウィンドウに結び付けて、ポップアップが開いているときにユーザーが親を閉じないようにする方法、または親が閉じたときにポップアップが自動的に閉じる方法です。親自体はメイン アプリケーションにはなりません。

4

1 に答える 1

4

これを行う最善の方法は、アプリケーションのメイン UI スレッドでウィンドウを表示することだと思います。

Dispatchertoを渡すことでそれを行うことができますDoWork()。しかし、計算の実行とエラーの表示の懸念を分離することも理にかなっています。したがって、代わりにできることはDoWork()、例外をスローして処理することTaskです. 継続はエラーが発生した場合にのみ実行され、メイン UI スレッドのコンテキストで実行されます。

private void button1_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(DoWork)
        .ContinueWith(
            task => ErrorBox.Show(task.Exception),
            CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
            TaskScheduler.FromCurrentSynchronizationContext());
}

private void DoWork()
{
    throw new Exception();
}

(ウィンドウを作成して表示すると仮定ErrorBox.Show()します。)

于 2013-04-22T20:03:56.443 に答える