WPF/Multithreading: UI Dispatcher in MVVM

27,098

Solution 1

I usually use Application.Current.Dispatcher: since Application.Current is static, you don't need a reference to a control

Solution 2

From Caliburn Micro source code :

public static class Execute
{
    private static Action<System.Action> executor = action => action();

    /// <summary>
    /// Initializes the framework using the current dispatcher.
    /// </summary>
    public static void InitializeWithDispatcher()
    {
#if SILVERLIGHT
        var dispatcher = Deployment.Current.Dispatcher;
#else
        var dispatcher = Dispatcher.CurrentDispatcher;
#endif
        executor = action =>{
            if(dispatcher.CheckAccess())
                action();
            else dispatcher.BeginInvoke(action);
        };
    }

    /// <summary>
    /// Executes the action on the UI thread.
    /// </summary>
    /// <param name="action">The action to execute.</param>
    public static void OnUIThread(this System.Action action)
    {
        executor(action);
    }
}

Before using it you'll have to call Execute.InitializeWithDispatcher() from the UI thread then you can use it like this Execute.OnUIThread(()=>SomeMethod())

Solution 3

I tend to have my ViewModels inherit from DependencyObject and ensure that they are constructed on the UI thread, which poises them perfectly to handle this situation - they have a Dispatcher property that corresponds to the UI thread's dispatcher. Then, you don't need to pollute your view with the ViewModel's implementation details.

Some other pluses:

  • Unit testability: you can unit test these without a running application (rather than relying on Application.Current.Dispatcher)
  • Loose coupling between View & ViewModel
  • You can define dependency properties on your ViewModel and write no code to update the view as those properties change.

Solution 4

The ViewModelBase of Catel has a Dispatcher property that you can use.

Share:
27,098
Shai UI
Author by

Shai UI

front-end developer in finance. especially html5/javascript/css based apps for mobile/desktop/tablets, node.js on the back-end. my main interests are heavy GUI, 2d/3d, data visualizations. check out my youtube channel: https://www.youtube.com/channel/UCJagBFh6ClHpZ2_EI5a3WlQ

Updated on September 12, 2020

Comments

  • Shai UI
    Shai UI over 3 years

    So say in an MVVM environment, I'm in a background thread and I'd like to run an update on a ui control. So normally I'd go myButton.Dispatcher.BeginInvoke(blabla) but I don't have access to myButton (because the viewmodel doesn't have access to the view's controls). So what is the normal pattern for doing this?

    (I guess there's always binding, but I'd like to know how to do it via the dispatcher)

  • Geert van Horrik
    Geert van Horrik over 13 years
    And how will you unit test your view models without an application object?
  • SRM
    SRM almost 13 years
    @Geert van Horrik You could mock the application object for unit testing your view models. Sorry for the necro comment - I just stumbled on this SO article while searching for a valid MVVM solution for multithreaded programming.
  • Ken Smith
    Ken Smith almost 12 years
    I still get the error if I use Dispatcher.CurrentDispatcher. It works correctly if I use Application.Current.Dispatcher.
  • Der_Meister
    Der_Meister about 10 years
    GetCurrentDispatcher method in DispatcherHelper class. catel.codeplex.com/SourceControl/latest#src/Catel.MVVM/…
  • aaronburro
    aaronburro over 3 years
    The fact that there may be multiple Dispatchers you have to worry about (while a bad design idea, but it happens) suggests that passing in a Dispatcher is a bad idea.
  • Thomas Levesque
    Thomas Levesque over 3 years
    @aaronburro nothing prevents you from putting it behind an abstraction that you can mock in unit tests.
  • aaronburro
    aaronburro over 3 years
    I think you've even got a nice blog post about doing exactly that
  • Tomas Karban
    Tomas Karban almost 3 years
    DependencyObject is quite heavy, what you really need is DispatcherObject. It has a simple implementation: its constructor calls Dispatcher.CurrentDispatcher and stores the value in a field for later use. If you cannot add a base class to your ViewModel, you can easily implement what DispatcherObject is doing.