I am trying to create a WPF application that presents a login view and after successful login, presents a first, second, and third page (like a wizard). Each "page" including the login view has its respective ViewModel
. I have a MainWindow.xaml
which holds four UserControls
one of which will be visible at any given state.
I am having trouble dealing with the orchestration of visibility. It makes the most sense to me that MainWindowViewModel
is the one that is responsible for keeping track of which UserControl
is the current visible one but I can't quite seem to get the code to work.
I will only show the relevant files for the MainWindow
and the LoginView
to keep things simpler.
MainWindow.xaml
<Grid>
<local:LoginView Visibility="{Not sure what to bind to here}" />
<local:PageOne Visibility="{Not sure what to bind to here}" />
<local:PageTwo Visibility="{Not sure what to bind to here}" />
<local:PageThree Visibility="{Not sure what to bind to here}" />
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
MainWindowViewModel.cs
public class MainWindowViewModel : BaseViewModel
{
public ICommand WindowClosingCommand { get; }
public MainWindowViewModel()
{
WindowClosingCommand = new WindowClosingCommand(this);
}
}
LoginView.xaml
<UserControl x:Class="MyProject.View.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProject.View"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1200">
<Grid>
<!-- UI Layout stuff here -->
</Grid>
</UserControl>
LoginView.xaml.cs
public partial class Login : UserControl
{
public Login()
{
InitializeComponent();
DataContext = new LoginViewModel();
}
}
LoginViewModel.cs
public class LoginViewModel : BaseViewModel
{
public ICommand ConnectCommand { get; }
public ICommand WindowClosingCommand { get; }
public LoginViewModel()
{
ConnectCommand = new ConnectCommand(this);
WindowClosingCommand = new WindowClosingCommand(this);
}
public string UserName { get; set; }
}
So as you can see, I want to avoid putting a ton of logic in the code behind files .xaml.cs
because that is best practice and I have a ViewModel
for which .xaml
file. Now, ordinarily, I would write something like:
public PageType CurrentPage;
public enum PageType
{
Login, PageOne, PageTwo, PageThree
}
public Visibility LoginVisibility
{
get { (CurrentPage == PageType.Login) ? Visibility.Visible : Visibility.Collapsed }
}
// Repeat for each of the other three pages
And then depending on if the "Next" or "Back" buttons were clicked on each page, I would set the CurrentPage
field properly.
However, if we refer back to my MainWindow.xaml
, I can't just do:
<local:LoginView Visibility="{Binding LoginVisibility}" />
Because LoginVisibility
does not exist in the LoginViewModel
which is what that user control's data context is. And it wouldn't feel right to put that field in there because all ViewModels
will then need to know their own visibility state and somehow communicate that up to the MainWindow
.
Basically, I am confused and unsure how to go about toggling between pages in my application. Any help or guidance would be greatly appreciated.
See Question&Answers more detail:
os