Search code examples
mvvmviewdatatemplatecontentcontrol

Switching Views in wpf mvvm


I have 2 views login and usermodule.I want to switch to usermodule if login is success.I have made datatemplates in mainwindow and a content control which gets bind by currentviewmodel.I made a switchview method in MainWindowViewModel which is called after successful login.As the login is successful the currentviewmodel gets changed to usermoduleviewmodel bur the view is not changing.

I have done like this: MainWinodow.xaml

 <Window.Resources>
    <DataTemplate  DataType="{x:Type VM:LoginViewModel}">
        <local:LoginView></local:LoginView>
    </DataTemplate>
    <DataTemplate DataType="{x:Type VM:MenuViewModel}">
        <local:MenuWindow />
    </DataTemplate>
    <DataTemplate DataType="{x:Type VM:UserModuleMapViewModel}">
        <local:UserModuleMapView />
    </DataTemplate>
</Window.Resources>
<Grid>
    <ContentPresenter x:Name="Pages" Content="{Binding CurrentViewModel}" 
    Grid.Row="1"/>
</Grid>

MainWindow.cs

 MainWindowViewModel mainVM = new MainWindowViewModel();
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = mainVM;

    }

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase
{
    readonly LoginViewModel _loginViewModel = new LoginViewModel();
    readonly MenuViewModel _menuViewModel = new MenuViewModel();
    readonly UserModuleMapViewModel _usermodmapViewModel = new UserModuleMapViewModel();

    public MainWindowViewModel()
    {
        CurrentViewModel = _loginViewModel;
    }

    private ViewModelBase _currentViewModel;

    public ViewModelBase CurrentViewModel
    {
        get
        {
            return _currentViewModel;
        }
        set
        {
            if (_currentViewModel == value)
                return;
            _currentViewModel = value;
            OnPropertyChanged("CurrentViewModel");
        }
    }

    public void switchView()
    {
        if (CurrentViewModel == _loginViewModel)
        {
            CurrentViewModel = _usermodmapViewModel;
        }
        else
        {
            CurrentViewModel = _loginViewModel;
        }
    }

}

LoginViewModel.cs

public LoginModel objmodel { get; set; }
    public ICommand LoginCommand { get; set; }
    public LoginModel _selectedItem { get; set; }
    public LoginModel SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            OnPropertyChanged("comboBoxItems");//need to check now its working properly
        }
    }

    readonly UserModuleMapViewModel _usermodmapViewModel = new UserModuleMapViewModel();

    public LoginViewModel()
    {
        getjobkeycodeCombobox();
        objmodel = new LoginModel();
        LoginCommand = new RelayCommand(() => Login());

    }
 public void Login()
    {
        try
        {
            UserIdInfo info = new UserIdInfo();

            {
                objmodel.job_Code_Key = SelectedItem.job_Code_Key;
                info.EMP_NO = objmodel.EMP_NO;
                info.Password = objmodel.Password;
                info.Job_Code_Key = objmodel.job_Code_Key;
                if (objmodel.EMP_NO == null || objmodel.EMP_NO == "" || objmodel.Password == null || objmodel.Password == "")
                {
                    MessageBox.Show("Please Enter the inputs of all the fields..!!");
                }
                else
                {
                    UserIdBL uidBL = new UserIdBL();
                    if (uidBL.isvalid(info))
                    {
                        MessageBox.Show("Success..!!");

                        MainWindowViewModel mwvm = new MainWindowViewModel();
                        mwvm.CurrentViewModel = _usermodmapViewModel;
                        //Messenger.Default.Send(new NotificationMessage("LoginSuccess"));

                    }
                    else
                    {
                    }
                }
            }
        }


    }

What mistake is done?Am I missing something >


Solution

  • The reason why the ContentPresenter is not updating is because the view is bound to a different instance of MainWindowViewModel. So the MainWindow DataContext is bound to an instance which is created here:

    // MainWindow.cs
    MainWindowViewModel mainVM = new MainWindowViewModel();
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = mainVM;
    }
    

    While the LoginViewModel creates a new instance of MainWindowViewModel which is not bound to anything:

    // LoginViewModel.cs
    MainWindowViewModel mwvm = new MainWindowViewModel();
    mwvm.CurrentViewModel = _usermodmapViewModel;
    

    That's why when you set mwvm.CurrentViewModel property in the Login method the binding is not triggered.

    So to achieve what you are trying to do you can subscribe MainWindowViewModel to login success message and set the current viewmodel there. Here is a simple example with MVVM Light messenger:

    // LoginViewModel.cs
    if (uidBL.isvalid(info))
    {
        MessageBox.Show("Success..!!");
    
        // MainWindowViewModel mwvm = new MainWindowViewModel();
        // mwvm.CurrentViewModel = _usermodmapViewModel;
    
        // send message to all subscribers
        Messenger.Default.Send(new NotificationMessage("LoginSuccess"));
    }
    
    // MainWindowViewModel.cs
    Messenger.Default.Register<NotificationMessage>(this, (message) =>
    {
        switch (message.Notification)
        {
            case "LoginSuccess":
                CurrentViewModel = _usermodmapViewModel;
                break;
            default:
                break;
        }
    });