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