22

ディスパッチャーを使用して UI スレッドで呼び出しを呼び出そうとすると、WPF アプリケーションが「ハング」したり、Wait 呼び出しでスタックしたりするように見える、やや複雑な WPF アプリケーションがあります。

一般的なプロセスは次のとおりです。

  1. ボタンのクリック イベントを処理する
  2. プレゼンターと UI の新しいインスタンスを作成し、Disconnectメソッドを呼び出す新しいスレッド (STA) を作成します。
  3. 切断してから、名前という名前の UI のプロパティを設定します
  4. Name のセッターは、次のコードを使用してプロパティを設定します。

    if(this.Dispatcher.Thread != Thread.CurrentThread)
    {
        this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate{
            this.Name = value; // Call same setter, but on the UI thread
        });
        return;
    }

    SetValue(nameProperty, value); // I have also tried a member variable and setting the textbox.text property directly.

私の問題は、ディスパッチャーの呼び出しメソッドが呼び出されると、毎回ハングしているように見え、呼び出しスタックは、呼び出し実装内でスリープ、待機、または参加していることを示していることです。

それで、私が間違っていること、明らかであるかどうか、またはこのプロパティ(およびその他)を設定するためにUIスレッドを呼び出すより良い方法がありますか?

編集:解決策は、スレッド デリゲートの最後 (たとえば、作業が実行されていた場所) で System.Windows.Threading.Dispatcher.Run() を呼び出すことでした - 助けてくれたすべての人に感謝します。

4

7 に答える 7

11

Invoke は同期的です - Dispatcher.BeginInvoke が必要です。また、コード サンプルでは、​​「SetValue」を「else」ステートメント内に移動する必要があると思います。

于 2008-11-05T06:01:49.290 に答える
5

新しいSTAスレッドを作成しているとのことですが、この新しいスレッドのディスパッチャーは実行されていますか?

「this.Dispatcher.Thread!= Thread.CurrentThread」から、別のディスパッチャーであることが期待されます。それ以外の場合はキューを処理しないことを確認してください。

于 2008-11-10T16:54:58.300 に答える
3

if (!this.Dispatcher.CheckAccess()) という意味だと思います

私も Invoke でハングアップしています。または、BeginInvoke ができる場合、デリゲートは呼び出されていません - 本ですべてを行っているようです :-(

于 2011-04-08T16:23:54.450 に答える
2

これはデッドロックのように聞こえます。これは通常、.Invoke を呼び出すスレッドが、UI スレッドが作業を完了するために必要なロック/ミューテックスなどを既に保持している場合に発生します。最も簡単な方法は、代わりに BeginInvoke を使用することです。この方法では、現在のスレッドは実行を継続でき、(おそらく) すぐにロックを解放し、UI がロックを取得できるようになります。または、問題のあるロックを特定できる場合は、意図的に一定期間解放することもできます。

于 2008-11-05T06:33:09.117 に答える
1

私も同様の問題を抱えています。答えはまだわかりませんが、あなたの

 if(this.Dispatcher.Thread != Thread.CurrentThread)
{
    this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate{
        this.Name = value; // Call same setter, but on the UI thread
    });
    return;
}

に置き換える必要があります

 if(this.Dispatcher.CheckAccess())
{
    this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate{
        this.Name = value; // Call same setter, but on the UI thread
    });
    return;
}

CheckAccessはIntellisenseには表示されませんが、そこにあり、この目的のためのものです。また、一般的にここでBeginInvokeが必要であることに同意しますが、この非同期を実行するとUIの更新が取得されないことがわかりました。残念ながら、同期して実行すると、デッドロック状態になります...

于 2011-03-07T04:19:12.360 に答える
0

これが古いスレッドであることは知っていますが、別の解決策があります。

同様の問題を修正しました。ディスパッチャは問題なく動作していたので...

DEBUG -> THREAD WINDOW を表示して、コードを実行しているすべてのスレッドを特定する必要がありました。

各スレッドをチェックすることで、デッドロックの原因となったスレッドをすぐに確認できました。

lock (locker) { ... }ステートメントと Dispatcher.Invoke() の呼び出しを組み合わせた複数のスレッドでした。

私の場合、特定のlock (locker) { ... }ステートメントを変更して、Interlocked.Increment(ref lockCounter).

デッドロックが回避されたため、これで問題は解決しました。

void SynchronizedMethodExample() {

    /* synchronize access to this method */
    if (Interlocked.Increment(ref _lockCounter) != 1) { return; }

    try {
    ...
    }
    finally {
        _mandatoryCounter--;
    }
}
于 2013-01-10T09:15:53.367 に答える