Ticket T800223
Visible to All Users

How to switch views based on value change from another viewmodel

created 6 years ago

Hi,
I am quite new to MVVM, and after searching your support center and the web, I still have problems to find a solution to this:
Basicly I want to show a LoginView with a viewmodel that checks the login data using a WCF service (this part is working).
The method of the WCF service returns a boolean if the login data was correct or not.
In case the login was correct, I want to switch the LoginView to my MainView.
My problem is, that I do not know, how to correctly submit the return value of my WCF service from my LoginViewViewModel to my MainWindowViewModel.
What I have done so far follows here:
I have a (themed) MainWindow which is defined like this:

XAML
<dx:ThemedWindow ...> <dx:ThemedWindow.DataContext> <ViewModels:MainWindowViewModel/> </dx:ThemedWindow.DataContext> <dx:ThemedWindow.Resources> <DataTemplate x:Key="LoginViewTemplate" DataType="{x:Type ViewModels:LoginViewModel}"> <Views:LoginView/> </DataTemplate> <DataTemplate x:Key="MainViewTemplate" DataType="{x:Type ViewModels:MainViewViewModel}"> <Views:MainView/> </DataTemplate> </dx:ThemedWindow.Resources> <Grid> <ContentControl Content="{Binding}"> <ContentControl.Style> <Style TargetType="{x:Type ContentControl}"> <Setter Property="ContentTemplate" Value="{StaticResource LoginViewTemplate}" /> <Style.Triggers> <DataTrigger Binding="{Binding IsLoggedIn}" Value="true"> <Setter Property="ContentTemplate" Value="{StaticResource MainViewTemplate}" /> </DataTrigger> </Style.Triggers> </Style> </ContentControl.Style> </ContentControl> </Grid> </dx:ThemedWindow>

My MainWindowViewModel pretty much only contains a boolean "IsLoggedIn" and an object "CurrentView"

My LoginViewViewModel:

C#
class LoginViewModel : ViewModelBase { private bool _loginSuccess; public bool LoginSuccess { get { return _loginSuccess; } set { SetProperty(ref _loginSuccess, value, () => LoginSuccess); } } // Constructor public LoginViewModel() { LoginCommand = new DelegateCommand(LoginCommandExecute); } // Command Definitions public DelegateCommand LoginCommand { get; set; } // Command Methods private void LoginCommandExecute() { if (ConnectionManager.Connection.IsLoginValid(_loginUser, _loginPassword)) { // WHAT TO DO HERE TO SWITCH THE VIEW IN THE MAIN WINDOW? } else { // No login for you :/ } } }

With the content control in the MainWindow I can switch between the two views when I toggle the "IsLoggedIn" boolean (manually). But how do I toggle this from the LoginViewViewModel class? Is this a good approach at all?

Thanks in advance and many greetings,
Sebastian

Answers approved by DevExpress Support

created 6 years ago

Hello,

In WPF, DataTemplates can be automatically loaded based on their DataType properties. To support this behavior in your application, do not define keys in your DataTemplates and do not define the ContentTemplate property explicitly. In this case, LoginViewTemplate will be loaded when the Content property contains the LoginViewModel object and MainViewTemplate for the MainViewViewModel object. This is default behavior in WPF, which is not related to our controls. You can learn more about it here:

Data Templating Overview
DataTemplate.DataType Property

Alternatively, you can implement a custom template selector: ContentControl.ContentTemplateSelector Property.

Thanks,
Andrey

    Other Answers

    created 6 years ago

    I am not sure if I understood your answer, but I randomly found your Messenger which solves my problem perfectly.

    My first (very basic) approach looks like this now:

    MainWindow:

    XAML
    <dx:ThemedWindow.DataContext> <ViewModels:MainWindowViewModel/> </dx:ThemedWindow.DataContext> <dx:ThemedWindow.Resources> <DataTemplate DataType="{x:Type ViewModels:LoginViewModel}"> <Views:LoginView /> </DataTemplate> <DataTemplate DataType="{x:Type ViewModels:MainViewViewModel}"> <Views:MainView /> </DataTemplate> </dx:ThemedWindow.Resources> <Grid> <ContentControl Content="{Binding CurrentView}"/> </Grid>

    MainWindowViewModel:

    C#
    private object _currentView; public object CurrentView { get { return _currentView; } set { SetProperty(ref _currentView, value, () => CurrentView); } } public MainWindowViewModel() { // set the first view to login CurrentView = new LoginViewModel(); // Register messenger to listen for login messages Messenger.Default.Register<LoginEventMessage>(this, OnLoginMessage); } private void OnLoginMessage(LoginEventMessage message) { if(message.LoginValidated) { CurrentView = new MainViewViewModel(); } }

    LoginViewModel:

    C#
    // Constructor public LoginViewModel() { LoginCommand = new DelegateCommand(LoginCommandExecute); } // Command Definitions public DelegateCommand LoginCommand { get; set; } // Command Methods private void LoginCommandExecute() { if (ConnectionManager.Connection.IsLoginValid(_loginUser, _loginPassword)) { // send message to main window to change the view Messenger.Default.Send(new LoginEventMessage(_loginUser, true)); } else { // No login for you :/ } }

    I feel like the Messanger is the perfect tool to communicate between different view models.

      Comments (1)
      Andrey Marten (DevExpress Support) 6 years ago

        If your final goal is to implement interaction between loosely coupled view models our Messenger is the right choice.

        As for the approach that I described, it is suitable when you change the content in your ContentControl to a different view model at runtime (for example, when login is completed successfully) and want to show a required view automatically.

        Feel free to contact us if you have additional questions.

        Thanks,
        Andrey

        Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

        Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.