2

Overview:

I have one MainWindow and two Views. One representing a Login Screen and the other one is representing the Dashboard. The LoginView is shown on StartUp. When the User presses the LoginButton the DashboardView should be shown.

Here's my Problem:

The underlying Command is beeing executed. The Constructor of DashboardViewModel is beeing called. And the View and ViewModel for Dashboard are connected via a DataTemplate. But the View or the InitializeComponent Method are not beeing called.

The LoginCommand looks like this:

LoginMainCommands is a RelayCommand Class derived from ICommand.

public class ButtonViewModel : LoginMainViewModel
{
    public ButtonViewModel()
    {
        _loginCommand = new LoginMainCommands(Login);
    }

    private LoginMainCommands _loginCommand;
    public LoginMainCommands LoginCommand
    {
        get { return _loginCommand; }
    }

    public void Login()
    {
        ViewModelLocator ObjViewModelLocator = new ViewModelLocator();
        ObjViewModelLocator.MWInstance.SwitchViewModel();
    }
}

The connection between the Views and the ViewModels is in ManWindow.xaml as follows:

<Window.Resources>
    <local:ViewModelLocator x:Key="ViewModelLocator"/>

    <DataTemplate DataType="{x:Type loginViewModel:LoginMainViewModel}">
        <loginView:LoginMainViewUserControl/>
    </DataTemplate>

    <DataTemplate DataType="{x:Type dashboardViewModel:DashboardMainViewModel}">
        <dashboardViews:DashboardMainViewUserControl/>
    </DataTemplate>
</Window.Resources>

To switch between the Views I added this Method in MainWindowViewModel:

public void SwitchViewModel()
{
   if (!isLoginView)
   {
      isLoginView = true;
      ViewModel = new LoginMainViewModel();
   }
   else
   {
      isLoginView = false;
      ViewModel = new DashboardMainViewModel();
   }
}

What I've tried so far:

I did almost everything this answer suggests. But I can't connect the Views and ViewModels in the App.xaml, cause then I can't use my ResourceDictionaries for Icons and Logos. But they are connected in MainWindow.xaml.

Later on I recognized in order for this to work only one Instance of MainWindowViewModel could exist because otherwise ViewModel would be null everytime a new Object is created. That's why I created ViewModelLocator like this answer suggests.

The weird part for me is when I change the if bracket in the SwitchViewModel Method to this:

if (!isLoginView)
{
   isLoginView = true;
   ViewModel = new DashboardMainViewModel();
}

Now DashboardMainViewModel is the default View to show and it does excatcly that it shows up.

I have no clue why the Dashboard Screen is not beeing shown.

I want to thank everybody in advance for your help and patience!

thatguy
  • 21,059
  • 6
  • 30
  • 40
LJSchmidt
  • 23
  • 5

1 Answers1

1

The problem is this line in the Login method in ButtonViewModel.

ViewModelLocator ObjViewModelLocator = new ViewModelLocator();

In your view model you create a new instance of the ViewModelLocator, which in turn creates a new instance of MainWindowViewModel on which you then call SwitchViewModel. That is the wrong instance.

You could solve this problem in many different ways, e.g.:

  • Make ViewModelLocator a singleton.

    You would set the DataContext like this, without creating an instance in the Window.Resources:

    DataContext="{Binding MainWindowViewModel, Source={x:Static local:ViewModelLocator.Instance}}"
    

    Then in ButtonViewModel you can directly call the SwitchViewModel through ViewModelLocator:

    ViewModelLocator.Instance.MWInstance.SwitchViewModel();
    
  • Pass a reference of the MainWindowViewModel to the other view models

    Passing the instance of MainWindowViewModel to the other view models in order to call SwitchViewModel works, but makes them tightly coupled and exposes more of the view model than necessary.

    Alternatively, you could create an interface ISwitchViewModels with a method SwitchViewModel that is implemented by MainWindowViewModel and pass it via the interface instead to hide the actual implementation.

  • Use events to communicate between view models

    Many WPF MVVM frameworks like Prism or Caliburn.Micro feature something called an Event Aggregator to communicate via events between view models and enable loose coupling. In this case you would not have to depend on a reference from ButtonViewModel to MainWindowViewModel, instead you would send a message to request changing the current view.

  • Use dependency injection to register the ViewModelLocator as singleton and pass it to view models

    I guess you are not familiar with dependency injection and it might be beyond the scope of this question, so this is just for further reading.

    Note that in this case the ViewModelLocator is not implemented as singleton, but only a single instance of it is created by a container and passed to all other types that specify this dependency.

    Understanding dependency injection

    What is dependency injection?

The weird part for me is when I change the if bracket in the SwitchViewModel Method to this: [...] Now DashboardMainViewModel is the default View to show and it does excatcly that it shows up.

That is not weird at all, since you directly assign the ViewModel property on the right instance of MainWindowViewModel without even using the ViewModelLocator.

thatguy
  • 21,059
  • 6
  • 30
  • 40