Search code examples
mvvmprismmef

How to handle UI interaction from view model without user request using MVVM, PRISM, and MEF


I am working on an application which is using WPF, MVVM, Prism, and MEF.

I am using a combination of navigation with request navigate, controllers with view management using region manager, and eventing via event aggregator to run the application in a single window. I'm using a view first approach similar to how the Stock Trader RI works. This works great when any view model code that would interact with the UI (busy indicator) is kicked off by the user, but when it is started behind the scenes there can be problems.

I know this may seem like a poor implementation, but I think I have a valid scenario. My particular example has to do with login.

Currently the application starts and loads the shell. The login view is loaded into the main content region of the shell. When the user clicks "login" a busy indicator is shown and the client application services login is executed. When the login is complete, the busy indicator goes away, and the screen is navigated to the user's home screen.

This works well because the navigation login and navigation are initiated by the user clicking the login button.

So now I have a new requirement that a user can select Auto Login on the login form, such that the next time the user starts the app, the login view will not show up and login will happen behind the scenes.

Now if I just want to call the auto login feature, there is no problem, this by itself has no UI interaction and will work fine. But login takes a few seconds and I want to display my busy indicator.

The problem is where do I initiate the auto login call? The shell view model constructor? The shell view model PartImportsSatisfied implementation? In any of these places, the shell view (which contains my busy indicator) isn't really loaded yet. As a result, none of the resources I need, like regions and region managers aren’t available. So what might be a good way for me to implement this:

Check if previous user should auto login (got this part figured out)

 If yes then
  Show busy indicator
  Attempt to auto login
  If auto login was success
   Hide busy indicator
   Navigate to user home screen
  Else
   Hide busy indicator
   Navigate to login screen
 Else
  Hide busy indicator
  Navigate to the login screen

Any ideas are greatly appreciated.


Solution

  • Implement an interface within your ShellViewModel which will deal with the concept of being loadable. Do not perform this logic within the constructor of the ShellViewModel as this is typically bad practice and should be used to instantiate objects at the most.

    public class ShellViewModel : ILoadable
    {
        public ShellViewModel()
        {
    
        }
    
        bool ILoadable.Load()
        {
             //this is where you can take care of your auto login
        }
    }
    

    You could then call this within your Bootstrapper class. If this were being done within another module you could call it within the IModule.Initialize method.

    I would also argue that this logic should get implemented within a service which could be called by the ShellViewModel as mentioned above or could in theory be called directly from the Bootstrapper class; allowing the ShellViewModel to potentially then make use of stateful data from within the service.