In WPF, like most UI frameworks, UI elements can only be updated from the thread they were created on. If you do background work, and want to affect the UI from a different thread, you’ll have to dispatch it. The Dispatcher class has a CheckAccess() method (which is marked as EditorBrowsableState.Never, making it invisible to intellisense for some reason.)

Here’s how you would normally use it:

delegate void CallMeDelegate(Button b);

void
CallMe(Button b)
{
    if (!Dispatcher.CheckAccess())
    {
        Dispatcher.Invoke(DispatcherPriority.Normal, new CallMeDelegate(CallMe), b);
        return;
    }

    b.Foreground = Brushes.Red;
}

You have to create a delegate, check for access and dispach if necessary. However, there’s a smarter way, if you allow for a bit of Reflection:

void CallMe(Button b)
{
    if (UIHelper.EnsureAccess(MethodBase.GetCurrentMethod(), this, b))
    {
        b.Foreground = Brushes.Red;
    }
}

What MethodBase.GetCurrentMethod() does is actually give you a method descriptor of the calling method (quite useful for a few scenarios! Too bad they don’t have a GetCallerMethod() as well…) The EnsureAccess() method then checks with the dispatcher if we’re on the right thread, and if not, dynamically dispatches it.

Last note: Dispatchers run a prioritized queue, so it can be handy to set the DispatcherPriority to something other than Normal. For example, if you set a Dependency Property’s value, and want to do something after the UI was updated, try dispatching it with ContextIdle priority.

For more information about Dispatchers, you should read Nick Kramer’s whitepaper.

Update: I also discovered the existence of the DispatcherSynchronizationContext, which inherits from the good old SynchronizationContext of .NET 2.0. The original one uses ThreadPool to queue items, while the WPF one uses the Dispatcher mechanism, which is more suitable for WPF. Note that this way you cannot specify a priority. I still believe the way I described above is slightly better.

Another Update: I’ve changed a few things in the implementation. Now it checks whether the object it receives is a DispatcherObject, and if so, uses its Dispatcher instead of the Application’s. This is good for (the rare) cases where your UI itself runs in more than one thread.

Attachment: UIHelper.rar

Tagged with:
 

2 Responses to Dispatch It

  1. Jan Kučera says:

    Hello!

    Very cool idea, thanks for sharng it. I only wanted to comment this one:

    "Too bad they don’t have a GetCallerMethod() as well…"

    Well there are two ways to get caller method, either by StackFrame class or using reflection (GetCurrentMethod calls InternalGetCurrentMethod(LookForMyCaller) and there is LookForMyCallersCaller option as well).

    I was indeed using it but I’ve found it is terribly bad idea as soon as I switched to the Release configuration, because with code optimalizations turned on, some methods can get optimized away! So the caller method in Debug and in Release configs can differ…

    Have a nice day!

    Jan

Set your Twitter account name in your settings to use the TwitterBar Section.