50

以下に、現在のスレッドが UI スレッドであることを確認 するアサーション メソッドEnsure.CurrentlyOnUiThread()を記述しました。

  • これは、Winforms UI スレッドを検出する際に信頼できますか?
  • 私たちのアプリは WPF と Winforms が混在していますが、有効な WPF UI スレッドを検出するにはどうすればよいですか?
  • これを行うより良い方法はありますか?おそらくコード契約?

保証.cs

using System.Diagnostics;
using System.Windows.Forms;

public static class Ensure
{
    [Conditional("DEBUG")]
    public static void CurrentlyOnUiThread()
    {
        if (!Application.MessageLoop)
        {
            throw new ThreadStateException("Assertion failed: not on the UI thread");
        }
    }
}
4

12 に答える 12

64

使用しないでください

if(Dispatcher.CurrentDispatcher.Thread == Thread.CurrentThread)
{
   // Do something
}

Dispatcher.CurrentDispatcher現在のスレッドにディスパッチャがない場合は、現在のスレッドにDispatcher関連付けられた新しいスレッドを作成して返します。

代わりにこのようにしてください

Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread);
if (dispatcher != null)
{
   // We know the thread have a dispatcher that we can use.
}

正しいディスパッチャがあること、または正しいスレッドにいることを確認するには、次のオプションがあります

Dispatcher _myDispatcher;

public void UnknownThreadCalling()
{
    if (_myDispatcher.CheckAccess())
    {
        // Calling thread is associated with the Dispatcher
    }

    try
    {
        _myDispatcher.VerifyAccess();

        // Calling thread is associated with the Dispatcher
    }
    catch (InvalidOperationException)
    {
        // Thread can't use dispatcher
    }
}

CheckAccess()インテリセンスで表示されVerifyAccess()ません。

また、これらの種類のものに頼らなければならない場合は、デザインが悪いことが原因である可能性があります。プログラム内のどのスレッドがどのコードを実行しているかを知っておく必要があります。

于 2013-01-11T14:41:52.720 に答える
25

WinForms内では、通常使用します

if(control.InvokeRequired) 
{
 // Do non UI thread stuff
}

WPF用

if (!control.Dispatcher.CheckAccess())
{
  // Do non UI Thread stuff
}

Generic 制約を使用して、これらのどれを呼び出す必要があるかを判断する小さなメソッドを作成することになるでしょう。例えば

public static bool CurrentlyOnUiThread<T>(T control)
{ 
   if(T is System.Windows.Forms.Control)
   {
      System.Windows.Forms.Control c = control as System.Windows.Forms.Control;
      return !c.InvokeRequired;
   }
   else if(T is System.Windows.Controls.Control)
   {
      System.Windows.Controls.Control c = control as System.Windows.Control.Control;
      return c.Dispatcher.CheckAccess()
   }
}
于 2011-02-28T15:04:26.433 に答える
21

WPFの場合、次を使用します。

public static void InvokeIfNecessary (Action action)
{
    if (Thread.CurrentThread == Application.Current.Dispatcher.Thread)
        action ();
    else {
        Application.Current.Dispatcher.Invoke(action);
    }
}

重要なのは、Dispatcher.CurrentDispatcher (現在のスレッドのディスパッチャーを提供します) をチェックする代わりに、現在のスレッドがアプリケーションまたは別のコントロールのディスパッチャーと一致するかどうかを確認する必要があることです。

于 2013-02-08T10:40:56.660 に答える
17

WPF の場合:

// You are on WPF UI thread!
if (Thread.CurrentThread == System.Windows.Threading.Dispatcher.CurrentDispatcher.Thread)

WinForms の場合:

// You are NOT on WinForms UI thread for this control!
if (someControlOrWindow.InvokeRequired)
于 2011-02-28T15:02:50.523 に答える
6

( WinForms Control.InvokeRequired) とDispatcher.CheckAccess(WPF) は大丈夫でしょうか?

于 2011-02-28T15:05:25.280 に答える
2

UI の知識をロジックに押し込んでいます。これは良い設計ではありません。

UIスレッドが乱用されないようにすることはUIの範囲内であるため、UIレイヤーはスレッドを処理する必要があります。

これにより、WinformsでIsInvokeRequired を使用し、WPF でDispatcher.Invokeを使用することもできます...また、同期および非同期の asp.net リクエスト内でコードを使用することもできます...

アプリケーション ロジック内の下位レベルでスレッド化を処理しようとすると、多くの不要な複雑さが追加されることが多いことが実際にわかりました。実際、実質的にフレームワーク全体が、この点を認めて書かれています。フレームワークのほとんどは、スレッド セーフではありません。スレッドの安全性を確保するのは、(より高いレベルでの) 呼び出し元次第です。

于 2011-02-28T15:06:37.823 に答える
1

WPF の場合:

スレッドの Dispatcher が実際に開始されているかどうかを知る必要がありました。スレッドで WPF クラスを作成すると、Dispatcher.Run().. 私はいくつかの反省で終わった:

public static class WpfDispatcherUtils
{
    private static readonly Type dispatcherType = typeof(Dispatcher);
    private static readonly FieldInfo frameDepthField = dispatcherType.GetField("_frameDepth", BindingFlags.Instance | BindingFlags.NonPublic);

    public static bool IsInsideDispatcher()
    {
        // get dispatcher for current thread
        Dispatcher currentThreadDispatcher = Dispatcher.FromThread(Thread.CurrentThread);

        if (currentThreadDispatcher == null)
        {
            // no dispatcher for current thread, we're definitely outside
            return false;
        }

        // get current dispatcher frame depth
        int currentFrameDepth = (int) frameDepthField.GetValue(currentThreadDispatcher);

        return currentFrameDepth != 0;
    }
}
于 2014-01-18T11:39:30.693 に答える
-4
Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId

これを確認するより良い方法は

于 2011-11-04T13:46:31.397 に答える