9

I'm making a WPF application making use of the MVVM light framework.

What I'm trying to do is have a login form in a view, when the user presses a button within that view it launches a LoginCommand for the attached ViewModel. From there I either want to launch a new window which holds the rest of the application, or simply switch views from the same window.

Currently I have it so that there is a view called MainView which has a content control inside bound to View1. However to switch to View2 I need to put the button for this on MainView, and not within View1 where it belongs.

Any advice?

benjgorman
  • 702
  • 10
  • 31

2 Answers2

9

Usually I do this one of two ways:

If the login window is a one-time thing required before starting the application, I will put it in the OnStartup() method of the Application object

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    // Login
    var login = new LoginDialog();
    var loginVm = new LoginViewModel();

    login.DataContext = loginVm;
    login.ShowDialog();

    if (!login.DialogResult.GetValueOrDefault())
    {
        // Error is handled in login class, not here
        Environment.Exit(0);
    }

    // If login is successful, show main application
    var app = new ShellView();
    var appModel = new ShellViewModel();

    app.DataContext = viewModel;
    app.Show();
}

The other way I usually do this is through a ShellViewModel or ApplicationViewModel which handles all my window management. This method uses DataTemplates to define each screen, and uses a ContentControl as a placeholder for the current screen in the ShellView or ApplicationView.

I usually combine this with an Event System of some kind, like Microsoft Prism's EventAggregator, so it can listen for messages of a specific type, such as OpenWindow or CloseWindow messages. If you're interested, I have a blog post about Communication between ViewModels that should give you a better idea of what an event system looks like.

For example, my ShellViewModel might start by displaying a LoginViewModel (a DataTemplate is used to tell WPF to draw the LoginViewModel with the LoginView), and it would subscribe to receive messages of type SuccessfulLogin. Once the LoginViewModel broadcasts a SuccessfulLogin message, the ShellViewModel will close the LoginViewModel and replace it with the ApplicationViewModel. You can see an example of this in my article on Navigation with MVVM

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • This seems like a good way to achieve it. Is there not a problem putting this functionality in the code behind, as opposed to in a view model? – benjgorman Feb 28 '12 at 20:38
  • 1
    @benjgorman The MVVM design pattern is meant to keep the UI code and application code separate, and I consider the code behind the `Application` class as a magic area between the two since it needs to initialize both the UI and the application objects to start the application. Honestly, I rarely have more than 1 window in my application. I prefer to use `DataTemplates` and `ContentControls` for managing the current content. You can see an example of this [here](http://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/) – Rachel Feb 28 '12 at 20:58
  • In your answer this part is causing he headaches. `if (!login.DialogResult.GetValueOrDefault()) { // Error is handled in login class, not here Environment.Exit(0); }` How do I bind this to a ICommand? I tried using a IPropertyChangedEvent but it fires before the login box appears. – benjgorman Feb 29 '12 at 15:12
  • @benjgorman The `LoginButton` which exists on the `LoginView` is bound to a command in the `LoginViewModel`. I'd have to look up exactly how I had it all hooked together, but if the login was successful, the `LoginView.DialogResult` got set to `true`. If not, it got set to `false`. Setting `this.DialogResult` in the `LoginView` caused the window to close automatically and return that `DialogResult` to whoever called `.ShowDialog()` – Rachel Feb 29 '12 at 17:55
  • @Rachel I tired the above using your first example, think I'm missing a step in the app.xaml.cs, as the login dialog doesn't close after successful login. Any thoughts? I made a gist of the three related classes: gist.github.com/BrianJVarley/44c74ab0663abe3cacb4 I also made a question on it: http://stackoverflow.com/questions/34257105/how-to-switch-data-context-on-successful-login – Brian Var Dec 13 '15 at 22:24
4

Put your views inside Page elements, inside your MainWindow create a Frame and point it's source to your first page.

From then on you can use the frame's NavigationService to navigate your frame to another view, much like a web browser.

SliverNinja - MSFT
  • 31,051
  • 11
  • 110
  • 173
karl.r
  • 961
  • 1
  • 11
  • 28