Dispatching in Silverlight

Anyone who has been building Silverlight and/or WPF applications for some time understands that there is a single UI thread that has special access requirements if you are going to be updating elements. In other words, if I spin off a new thread, I cannot arbitrarily impact the UI unless I get back to the UI thread using a dispatcher.

Fortunately, Silverlight makes it very easy to find your dispatcher, because it is a property on any UIElement that exists, including your own user control. If I need to make sure a thread executes on the UI thread, I simply do something like this:

this.Dispatcher.BeginInvoke(()=>MyFunc()); 

Things get a little more tricky if you are trying to access the dispatcher from an entity that doesn’t know about the UI thread … for example, a view model.

Let’s say you have a view model that needs to kick of a separate thread to do some work, and then update properties that are bound to the UI. By design, the view model interacts with services and exposes properties but it doesn’t know about the view. We could sell out by giving it a Dispatcher property, but that could get ugly in scenarios such as unit tests where there simply may not be a UI thread.

Once again I’m happy to go back to the C# keywords that make our lives easier. In the past, I would have simply raised an event, “I need this” and passed some arguments, but with Action at our fingertips, it’s so much easier!

In fact, this is all it really takes … note the use of an action that takes a, um, ahem, action:

public class ViewModel 
{

   public Action<Action> UIAction { get; set; }

   public ViewModel()
   {
      UIAction = ((uiAction)=>uiAction());
   }

}

Seems fairly simple, doesn’t it? Any time I am going to update one of my databound properties in a disconncted thread, I simply do this:

UIAction(()=>{ viewModel.Property = "New value";}); 

Right now, this isn’t doing anything really interesting, because the action delegate simply calls the action we pass … very boring, really. It will pass unit tests and all of that jazz … so why’d I do it?

Because, once I bring the view model into an actual view, then I’ll need to give it the dispatcher. Then, I can do something like this:

ViewModel viewModel = new ViewModel();
this.DataContext = viewModel; // or bind it with MEF to make it more fun
viewModel.UIAction = ((uiAction) => Dispatcher.BeginInvoke(()=>uiAction())); 

Now we’ve set it up so that when you call the action with an action, the action is to perform the action inside the dispatcher thread (got all that?). Now the view model plays equally well in the view and out of the view. It is still ignorant of what the view is or even that there is a dispatcher, and only needs to know that updating protected properties should be wrapped in the UIAction.

Let’s save the argument over whether we should even be spinning threads from the view model that modify the UI thread for another day, mmmmm kay?

Jeremy Likness

View Comments

  • I do like the solution, it works and is simple. However, for me when I use the line:
    [code]
    viewModel.UIAction = ((uiAction) => Dispatcher.BeginInvoke(()=>uiAction()));
    [/code]
    I get the error: "Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type"
    Upon much reflection and reverse engineering (I had never seen Action before) I realised it would work if I changed the line to:
    [code]
    viewModel.UIAction = ((uiAction) => Dispatcher.BeginInvoke(uiAction));
    [/code]
    Not earth shattering I know, but it would have saved someone as slow as me a couple of days! :)
    Thanks for the ideas,
    Leon

  • Very nice Jeremy. I'm dealing with a 3rd party GPS control which you have to subscribe to events to deal with updating properties. This worked out perfectly for now.
    Thanks.

  • Hi Jeremy,
    Thanks for the very helpful post. I have one question. If we use this
    viewModel.UIAction = ((uiAction) => Dispathcer.BeginInvoke(uiAction));
    are we not directly trying to access the View from ViewModel?

  • This is actually dated now - the best way to get the dispatcher is like this:
    Action myaction = ()=>DoSomething();
    var dispatch = Deployment.Current.Dispatcher;
    if (dispatch.CheckedAccess)
    {
    myaction();
    }
    else
    {
    dispatch.BeginInvoke(myaction());
    }
    This will work from anywhere.

  • Thanks for helping me in dispatching I am a beginner in Silverlight and found it very useful... Thanks:)

Recent Posts

8-Step AWS to Microsoft Azure Migration Strategy

Microsoft Azure and Amazon Web Services (AWS) are two of the most popular cloud platforms.…

5 days ago

How to Navigate Azure Governance

 Cloud management is difficult to do manually, especially if you work with multiple cloud…

2 weeks ago

Why Azure’s Scalability is Your Key to Business Growth & Efficiency

Azure’s scalable infrastructure is often cited as one of the primary reasons why it's the…

4 weeks ago

Unlocking the Power of AI in your Software Development Life Cycle (SDLC)

https://www.youtube.com/watch?v=wDzCN0d8SeA Watch our "Unlocking the Power of AI in your Software Development Life Cycle (SDLC)"…

1 month ago

The Role of FinOps in Accelerating Business Innovation

FinOps is a strategic approach to managing cloud costs. It combines financial management best practices…

1 month ago

Azure Kubernetes Security Best Practices

Using Kubernetes with Azure combines the power of Kubernetes container orchestration and the cloud capabilities…

2 months ago