4

メインウィンドウ(スレッドA )で、ユーザーが待機している間に何らかの作業を行う新しいスレッド(スレッドB )を開始します。

エラーが発生した場合、またはユーザーからの追加情報が必要な場合、スレッドBはイベントを発生させます。スレッドAはこれらのイベントをリッスンします。

スレッドAのイベントリスナーで、ユーザーにダイアログメッセージを表示する必要があります。カスタムダイアログウィンドウがあり、を使用して表示しますdialogWindow.showDialog()。これは正常に機能しますが、ダイアログの所有者を設定しようとするとエラーが発生します。これを行いますdialogWindow.Owner = Window.GetWindow(this)

私が得るエラーは次のとおりです。別のスレッドがオブジェクトを所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません。

別のスレッドから発生するイベントをリッスンする正しい方法は何ですか?

4

3 に答える 3

7

イベントリスナーコードは、イベントを発生させるスレッドで暗黙的に実行されるため、イベントリスナーはスレッドにバインドされません。

イベント処理の結果としてUIに何かを表示したい場合は、自分でマーシャリングを行う必要があります。そんな感じ:

void OnEvent(object sender, EventArgs args)
{
    // runs in the event sender's thread
    string x = ComputeChanges(args);
    Dispatcher.BeginInvoke((Action)(
        () => UpdateUI(x)
    ));
}

void UpdateUI(string x)
{
    // runs in the UI thread
    control.Content = x;
    // - or -
    new DialogWindow() { Content = x, Owner = this }.ShowDialog();
    // - or whatever
}

つまり、UIに触れることなく、バックグラウンドスレッドで(もしあれば)計算を実行することが望ましいです。その後、UIに必要な変更がわかったら、UIスレッドでUI更新コードを実行します。

これDispatcherはコントロールのプロパティであるため、コードがUIの一部である場合は、ディスパッチャーを無料で利用できます。それ以外の場合は、任意のコントロール(たとえばcontrol.Dispatcher)からディスパッチャを取得できます。

于 2012-04-25T12:19:58.103 に答える
3

確かに->私たちがしていることはSynchronizationContextを使用することです。したがって、新しいスレッドを開始するときは、(UIスレッドで)現在のコンテキストをキャプチャし、それをパラメーターとして2番目のスレッドに渡します。

次に、2番目のスレッドでイベントを発生させたい場合は、次のようにします。

    if (_uiThreadId != Thread.CurrentThread.ManagedThreadId)
    {
        _uiContext.Post(
            new SendOrPostCallback(delegate(object o) { OnYourEvent((EventArgs)o); }),
            e);
    }
    else
        OnYourEvent(e);
于 2012-04-25T12:18:55.593 に答える
3

バックグラウンドスレッドからUIスレッドにイベントを発生させる正しい方法は、イベントをそのディスパッチャーで発生させる必要があるということです。ここで重要なのは、UIthreadのディスパッチャーを事前に取得することです。

UIDisaptcher.BeginInvoke((ThreadStart)(()=> RaiseEventToUIThread()));

UIスレッドは、発生したイベントをリッスンするときに、Ownerプロパティを設定できます(ウィンドウはUIスレッドによって作成されたため)。

于 2012-04-25T12:24:56.043 に答える