Dispatch It

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
Published 02-16-2007 12:57 PM by aelij
Filed under: ,

Comments

# http://learnwpf.com/posts/post.aspx?postid=0272ec10-d776-4a27-aded-b223cc83f27b

Friday, March 09, 2007 2:00 AM by TrackBack

# re: Dispatch It

Sunday, September 07, 2008 2:37 PM by Jan Kučera

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

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Please add 4 and 1 and type the answer here:
Powered by Community Server (Non-Commercial Edition), by Telligent Systems