52

I've written an assertion method Ensure.CurrentlyOnUiThread(), below, that checks that the current thread is a UI thread.

  • Is this going to be reliable in detecting the Winforms UI thread?
  • Our app is mixed WPF and Winforms, how best to detect a valid WPF UI thread?
  • Is there a better way to do this? Perhaps code contracts?

Ensure.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");
        }
    }
}
chillitom
  • 24,888
  • 17
  • 83
  • 118

12 Answers12

67

Don't use

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

Dispatcher.CurrentDispatcher will, if the current thread do not have a dispatcher, create and return a new Dispatcher associated with the current thread.

Instead do like this

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

To be sure you have the correct dispatcher or are on the correct thread you have the following options

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() and VerifyAccess() do not show up in intellisense.

Also, if you have to resort to these kinds of things its likely due to bad design. You should know which threads run what code in your program.

CodeMonkey
  • 3,418
  • 4
  • 30
  • 53
  • 6
    I've tried the provided solution, however came to the conclusion it doesn't work from a background thread initialized by a Task.Run(). The solution provided here worked fine: http://stackoverflow.com/a/13726324/249948. – Herman Cordes Mar 06 '14 at 11:20
  • 2
    NOTE that the solution linked by Herman Cordes is for WPF. For WinForms, use CodeMonkey's answer, or simply do `if (System.Windows.Forms.Application.MessageLoop)`. – ToolmakerSteve May 15 '16 at 22:34
28

For WPF, I use the following:

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

The key is instead of checking Dispatcher.CurrentDispatcher (which will give you the dispatcher for the current thread), you need to check if the current thread matches the dispatcher of the application or another control.

Curtis
  • 1,552
  • 15
  • 20
  • 2
    This is the only solution here that works reliably. The top-voted answer often returns a non-null dispatcher for the thread pool threads. – Kirk Woll Jul 20 '17 at 23:17
  • Found that the accepted answer sometimes return non-null dispatcher when you're on a background thread. This seems to be more reliable. – Fred Oct 26 '18 at 12:00
  • In UI thread execution branch it may also be useful to add DoEvents suggested here https://stackoverflow.com/a/4502200/282694 to force action result update on UI (just "{ action(); DoEvents(); }" instead of "action()") – sarh Jan 15 '22 at 08:46
  • 1
    Another observation after one day of using this. If it is used inside lock or parallel processing - this can cause a dead lock on Invoke(). Suggested solution is to replace it with BeginInvoke() but it will be async execution which in many cases OK to just update UI, but can be not OK if result of this execution is used in the next steps. – sarh Jan 15 '22 at 22:56
25

Within WinForms you would normally use

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

for WPF

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

I would probably write a little method that uses a Generic constraint to determine which of these you should be calling. e.g.

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()
   }
}
Ian
  • 33,605
  • 26
  • 118
  • 198
  • 2
    thanks for those, i've found InvokeRequired to be quite unreliable, esp if control doesn't yet have a handle or is being dispose, also I'd like an assertion that doesn't need access to the control. – chillitom Feb 28 '11 at 15:06
  • 1
    Why would you be calling InvokeRequired if your item is being disposed or hasn't yet been correctly initialized? Using InvokeRequired is standard... – Ian Feb 28 '11 at 15:09
  • you're right, I shouldn't and that should be the subject of some other checks. – chillitom Feb 28 '11 at 15:14
  • Just to check, you do realise you can update UI elements from the none UI threads via invoking don't you? – Ian Feb 28 '11 at 15:25
  • @Ian, yip I grasped that one. This is more an attempt to put some logic in to fail fast when the program arrives at a point in the code that assumes it's already on the GUI thread but is fact on the wrong thread. Not every method has access to a control to perform the check. Hence the question. – chillitom Feb 28 '11 at 20:43
  • 1
    @Ian - Nice, convenient method. NOTE: Return type should be `bool` not `void`. And method should end with `else throw new InvalidArgumentException...` – ToolmakerSteve May 13 '17 at 09:22
18

For WPF:

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

For WinForms:

// You are NOT on WinForms UI thread for this control!
if (someControlOrWindow.InvokeRequired)
ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Matěj Zábský
  • 16,909
  • 15
  • 69
  • 114
  • 3
    The latter case is only true if `someControlorWindow` was *created on* the UI thread which is hoping to be checked for. It is perfectly "okay" to have multiple Windows UI threads. –  Jul 11 '11 at 20:19
  • 3
    @pst - It might be okay, but it's rare. In almost all cases, WPF and WinForms apps have exactly one UI thread. – Bevan Nov 14 '12 at 23:10
  • 9
    With regard to WPF, this answer is incorrect. Remember that EVERY THREAD has a dispatcher. So basically in your statement you are asking "Is this thread equal to the thread assocated with the dispatcher of this thread?" Or, condensed a little more, you are asking "Is this thread equal to this thread?" Well, yes of course it is. See MS documentation here: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.checkaccess.aspx#feedback – Sam Dec 17 '12 at 23:10
  • 4
    Every thread in WPF DON'T have a dispatcher! BUT they can get one! Dispatcher.CurrentDispatcher will create and return a new Dispatcher if the current thread don't have one!!! – CodeMonkey Jan 11 '13 at 13:55
  • @Jepa, my comment is correct. Every thread DOES have a dispatcher. The dispatcher may in fact be lazily created but that is irrelevent to the topic being discussed. The point I made is about the relationship between the tread and the dispatcher. See here: http://stackoverflow.com/questions/5015278/dispatcher-to-thread-relationships-in-wpf – Sam Feb 06 '13 at 23:11
  • 1
    @Sam To my opinion your statement is incorrect, the proper way to say is: every thread can potentially have a dispatcher associated with it, if required. Relationship (dispatcher-thread) is 0..1 to 1, not 1:1. How can A contain B, if B is not created (Null)? – Goran Jul 19 '13 at 22:44
  • 5
    @Goran - what you say is true, BUT you misunderstand Sam's point. The call to CurrentDispatcher will never return a dispatcher for a DIFFERENT thread than Thread.CurrentThread. Instead, if CurrentThread lacks a dispatcher, it will create one for it -- and that dispatcher's thread will be CurrentThread. So the test will always evaluate to `CurrentThread == CurrentThread`, so `true`. So this answer is wrong. – ToolmakerSteve May 15 '16 at 22:02
6

Maybe Control.InvokeRequired (WinForms) and Dispatcher.CheckAccess (WPF) are OK for you?

Adi Lester
  • 24,731
  • 12
  • 95
  • 110
Alex F
  • 42,307
  • 41
  • 144
  • 212
2

You're pushing knowledge of your UI down into your logic. This is not a good design.

Your UI layer should be handling threading, as ensuring the UI thread isn't abused is within the purview of the UI.

This also allows you to use IsInvokeRequired in winforms and Dispatcher.Invoke in WPF... and allows you to use your code within synchronous and asynchronous asp.net requests as well...

I've found in practice that trying to handle threading at a lower level within your application logic often adds lots of unneeded complexity. In fact, practically the entire framework is written with this point conceded--almost nothing in the framework is thread safe. Its up to callers (at a higher level) to ensure thread safety.

  • 1
    Sure, but it's not part of the design, it's part of a serious of checks and measures I can put in place to ensure that other parts of the system are behaving correctly/as expected. When working with spaghetti legacy code I find these kind of assertions very useful. – chillitom Feb 28 '11 at 15:16
  • @chillitom my condolences. I think if I were in your position I'd be tempted to roll the dice, fail fast, and learn which strands of the spaghetti are vulnerable to threading issues, and insulate them at the highest level possible. –  Feb 28 '11 at 18:20
1

Here is a snippet of code I use in WPF to catch attempts to modify UI Properties (that implement INotifyPropertyChanged) from a non-UI thread:

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        // Uncomment this to catch attempts to modify UI properties from a non-UI thread
        //bool oopsie = false;
        //if (Thread.CurrentThread != Application.Current.Dispatcher.Thread)
        //{
        //    oopsie = true; // place to set a breakpt
        //}

        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
Chris Bennet
  • 587
  • 5
  • 13
1

For WPF:

I've needed to know is Dispatcher on my thread is actually started, or not. Because if you create any WPF class on the thread, the accepted answer will state that the dispatcher is there, even if you never do the Dispatcher.Run(). I've ended up with some reflection:

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;
    }
}
Gman
  • 1,781
  • 1
  • 23
  • 38
1

You can compare thread ids like this :

       var managedThreadId = System.Windows.Threading.Dispatcher.FromThread(System.Threading.Thread.CurrentThread)?.Thread.ManagedThreadId;
        var dispatcherManagedThreadId = System.Windows.Application.Current.Dispatcher.Thread.ManagedThreadId;
        if (managedThreadId == dispatcherManagedThreadId)
        {
             //works in ui dispatcher thread
        }
Seçkin Durgay
  • 2,758
  • 4
  • 27
  • 36
0

Using MVVM it is actually fairly easy. What I do is put something like the following in, say, ViewModelBase...

protected readonly SynchronizationContext SyncContext = SynchronizationContext.Current;

or...

protected readonly TaskScheduler Scheduler = TaskScheduler.Current; 

Then when a particular ViewModel needs to touch anything "observable", you can check the context and react accordingly...

public void RefreshData(object state = null /* for direct calls */)
{
    if (SyncContext != SynchronizationContext.Current)
    {
        SyncContext.Post(RefreshData, null); // SendOrPostCallback
        return;
    }
    // ...
}

or do something else in the background before returning to context ...

public void RefreshData()
{
    Task<MyData>.Factory.StartNew(() => GetData())
        .ContinueWith(t => {/* Do something with t.Result */}, Scheduler);
}

Normally, if you follow MVVM (or any other architecture) in an orderly fashion, it is easy to tell where the responsibility for UI synchronization will be situated. But you can basically do this anywhere to return to the context where your objects are created. I'm sure it would be easy to create a "Guard" to handle this cleanly and consistently in a large and complex system.

I think it makes sense to say that your only responsibility is to get back to your own original context. It is a client's responsibility to do the same.

Ben Stabile
  • 71
  • 1
  • 2
  • Readers should know that this approach is not reliable on .NET 4. There is a bug that can leave SynchronizationContext.Current null on the UI thread. See http://stackoverflow.com/questions/4659257. – Wallace Kelly Jan 23 '14 at 21:00
0

FOR WPF:

Here's a snippet based on the top answer, using a delegate meaning it is very generic.

        /// <summary>
        /// Invokes the Delegate directly on the main UI thread, based on the calling threads' <see cref="Dispatcher"/>.
        /// NOTE this is a blocking call.
        /// </summary>
        /// <param name="method">Method to invoke on the Main ui thread</param>
        /// <param name="args">Argumens to pass to the method</param>
        /// <returns>The return object of the called object, which can be null.</returns>
        private object InvokeForUiIfNeeded(Delegate method, params object[] args)
        {
            if (method == null) throw new ArgumentNullException(nameof(method));

            var dispatcher = Application.Current.Dispatcher;

            if (dispatcher.Thread != Thread.CurrentThread)
            {
                // We're on some other thread, Invoke it directly on the main ui thread.
                return dispatcher.Invoke(method, args);
            }
            else
            {
                // We're on the dispatchers' thread, which (in wpf) is the main UI thread.
                // We can safely update ui here, and not going through the dispatcher which safes some (minor) overhead.
                return method.DynamicInvoke(args);
            }

        }

        /// <inheritdoc cref="InvokeForUiIfNeeded(Delegate, object[])"/>
        public TReturn InvokeForUiIfNeeded<TReturn>(Delegate method, params object[] args)
            => (TReturn) InvokeForUiIfNeeded(method, args);

The second method allows for a more type safe return type. I've also added some overloads that automatically take the Func and Action parameters in my code, e.g:

        /// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
        private void InvokeForUiIfNeeded(Action action)
            => InvokeForUiIfNeeded((Delegate) action);

Note; the Func and Action inherit from Delegate so we can just cast it.

You could also add your own generic overloads that take actions, i did not bother creating a bunch of overloads but you definitely could e.g;

        /// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
        private void InvokeForUiIfNeeded<T1>(Action<T1> action, T1 p1)
            => InvokeForUiIfNeeded((Delegate)action, p1);

        /// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
        private TReturn InvokeForUiIfNeeded<T1, TReturn>(Func<T1, TReturn> action, T1 p1)
            => (TReturn)InvokeForUiIfNeeded((Delegate)action, p1);
sommmen
  • 6,570
  • 2
  • 30
  • 51
-4
Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId

Is a better way to check this

chown
  • 51,908
  • 16
  • 134
  • 170