简体   繁体   English

WPF c# 尝试登录成功后如何切换到仪表板视图? 这是我的代码

[英]WPF c# How can I switch to dashboard view after successfull login attemp? Here's m code

Here is my xaml code.这是我的 xaml 代码。 I want to update the current view after the successfull login attempt.我想在成功登录尝试后更新当前视图。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Content="Login Page" 
            Command="{Binding UpdateCurrentViewModelCommand}"
            CommandParameter="LoginView"/>
    <Button Content="Register Page" 
            Command="{Binding UpdateCurrentViewModelCommand}"
            CommandParameter="RegisterView"
            Grid.Row="1"/>
    <ContentControl Content="{Binding CurrentView}" Grid.Row="2"/>
</Grid>
public class MainViewModel : BaseViewModel
{
    private BaseViewModel _currentView = new LoginViewModel();
    public BaseViewModel CurrentView
    {
        get
        {
            return _currentView;
        }
        set
        {
            _currentView = value;
            OnPropertyChanged(nameof(CurrentView));
        }
    }
    public ICommand UpdateCurrentViewModelCommand { get; set; }
    public MainViewModel()
    {
        UpdateCurrentViewModelCommand = new RelayCommand(UpdateCurrentView);
    }

    private void UpdateCurrentView(object obj)
    {
        if (obj.ToString() == "LoginView")
        {
            CurrentView = new LoginViewModel();
        }
        else if (obj.ToString() == "RegisterView")
        {
            CurrentView = new RegisterViewModel();
        }
        else if (obj.ToString() == "DashboardView")
        {
            CurrentView = new DashboardViewModel();
        }
    }
}

Here when user logs in it should update the current view, it is executing the command also I am getting the value in command parameter and it also updating the property CurrentView in MainViewModel but the problem is, it is not updating the UI the view is not displaying...这里当用户登录时它应该更新当前视图,它正在执行命令我也在命令参数中获取值并且它还在 MainViewModel 中更新属性CurrentView但问题是,它没有更新 UI 视图不是显示...

public class LoginViewModel : BaseViewModel
{
    private string _email;
    public string Email
    {
        get
        {
            return _email;
        }
        set
        {
            _email = value;
            OnPropertyChanged(nameof(Email));
        }
    }
    private string _password;
    public string Password
    {
        get
        {
            return _password;
        }
        set
        {
            _password = value;
            OnPropertyChanged(nameof(Password));
        }
    }
    public ICommand LoginCommand { get; set; }
    private StringBuilder ErrorMessages { get; set; } = new StringBuilder();
    public LoginViewModel()
    {
        LoginCommand = new RelayCommandAsync(async (para) => await LoginUser(para));
    }
    private async Task LoginUser(object para)
    {
        SqlConnector sqlConnector = new SqlConnector();
        if (ValidateForm() == false)
        {
            MessageBox.Show(ErrorMessages.ToString());
            return;
        }
        User user = await sqlConnector.FindUserByEmail(Email);
        if (user == null)
        {
            MessageBox.Show("Incorrect username or password");
            return;
        }
        IPasswordHasher passwordHasher = new PasswordHasher();
        var passwordResult = passwordHasher.VerifyHashedPassword(user.PasswordHash, Password);
        if (passwordResult == PasswordVerificationResult.Success)
        {
            MessageBox.Show("Login success.");
            //here is the problem...I am telling my MainViewModel's CurrentView property to update 
            but it's not listening to me. 
                //new MainViewModel().UpdateCurrentViewModelCommand.Execute("DashboardView");
            new MainViewModel().CurrentView = new DashboardViewModel();
        }
        else
        {
            MessageBox.Show("Incorrect username or password");
        }
        ClearProperties();
    }
    private bool ValidateForm()
    {
        ErrorMessages.Clear();
        bool isValid = true;
        if (string.IsNullOrWhiteSpace(Email))
        {
            isValid = false;
            ErrorMessages.Append("Email cannot be empty\n");
        }
        if (string.IsNullOrWhiteSpace(Password))
        {
            isValid = false;
            ErrorMessages.Append("Password cannot be empty\n");
        }
        return isValid;
    }
    private void ClearProperties()
    {
        Email = Password = null;
    }

This is not working as you are creating a new instance of MainViewModel after the successful login.这不起作用,因为您在成功登录后创建了MainViewModel的新实例。 This is not the instance that is the DataContext of your view.这不是您视图的DataContext实例。

You could pass a reference to the MainViewModel instance eg, via the constructor to the LoginViewModel .您可以传递对MainViewModel实例的引用,例如,通过构造函数传递给LoginViewModel But since the LoginViewModel doesn't really depend on the MainViewModel I wouldn't do that.但是由于LoginViewModel并不真正依赖于MainViewModel ,所以我不会那样做。
Instead I suggest one of the two following solutions.相反,我建议使用以下两种解决方案之一。 Generally your page view models shouldn't care about the content navigation.通常,您的页面视图模型不应该关心内容导航。 This should be only responsibility of the parent navigation view model, that already knows navigation details like current page or next page etc. Both examples follow this idea.这应该是父导航视图 model 的唯一责任,它已经知道导航详细信息,如当前页面或下一页等。两个示例都遵循这个想法。

Also note that since you are creating new page view models every time the user navigates, you will lose all the content.另请注意,由于每次用户导航时您都在创建新的页面视图模型,因此您将丢失所有内容。 Coming back to a previous page would show a blank initial page.返回上一页将显示一个空白的初始页面。 Also the switch is very bad in terms of extensibility.此外, switch在可扩展性方面非常糟糕。 Adding new pages is not very nice and would blow your UpdateCurrentView method.添加新页面不是很好,并且会破坏您的UpdateCurrentView方法。

I refactored your code to show an easy way to keep the page navigation simple and extensible.我重构了您的代码以展示一种简单的方法来保持页面导航的简单性和可扩展性。 This are only small changes: Add an enum to replace strings in order to enable Intellisense and compiletime type checking support and add a Dictionary to replace the switch :这只是一些小改动:添加一个enum来替换字符串以启用 Intellisense 和编译时类型检查支持,并添加一个Dictionary来替换switch

// Enum used to identify the requested page e.g as CommandParameter
public enum PageId
{
   None = 0, LoginView, RegisterView, DashboardView
}

// Use a Dictionary to navigate to content based on the PageId enum
public class MainViewModel : BaseViewModel
{
    private Dictionary<PageId, BaseViewModel> Pages { get; set; }

    public MainViewModel()
    {
        this.Pages = new Dictionary<PageId, BaseViewModel>
        {
            { PageId.LoginView, new LoginViewModel() },
            { PageId.RegisterView, new RegisterViewModel() },
            { PageId.DashboardView, new DashboardViewModel() }
       };
    }

    private void UpdateCurrentView(object commandParameter)
    {
        if (commandParameter is PageId pageId
          && this.Pages.TryGetValue(pageId, out BaseViewModel nextPage))
        {
            this.CurrentView = nextPage;
        }
    }
}

<!-- Modified view to use the enum -->
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Content="Login Page" 
            Command="{Binding UpdateCurrentViewModelCommand}"
            CommandParameter="{x:Static PageId.LoginView}"/>
    <Button Content="Register Page" 
            Command="{Binding UpdateCurrentViewModelCommand}"
            CommandParameter="{x:Static PageId.RegisterView}"
            Grid.Row="1"/>
    <ContentControl Content="{Binding CurrentView}" Grid.Row="2"/>
</Grid>

Solution 1: LoginSuccessful Event方案一: LoginSuccessful事件

You can expose a LoginSuccessful event, that the navigation view model can listen to:您可以公开一个LoginSuccessful事件,导航视图 model 可以监听:

MainViewModel.cs MainViewModel.cs

public class MainViewModel : BaseViewModel
{
    private Dictionary<PageId, BaseViewModel> Pages { get; set; }

    public MainViewModel()
    {
        this.Pages = new Dictionary<PageId, BaseViewModel>
        {
            { PageId.RegisterView, new RegisterViewModel() },
            { PageId.DashboardView, new DashboardViewModel() }
       };
    
       var loginView = new LoginViewModel();
       loginView.LoginSuccessful += OnLoginSuccessful;
       this.Pages.Add(PageId.LoginView, loginView);
    }

    private void UpdateCurrentView(object commandParameter)
    {
        if (commandParameter is PageId pageId
          && this.Pages.TryGetValue(pageId, out BaseViewModel nextPage))
        {
            this.CurrentView = nextPage;
        }
    }

    private void OnLoginSuccessful(object sender, EventArgs e)
    {
        var loginViewModel = sender as LoginViewModel;
        loginViewModel.LoginSuccessful -= OnLoginSuccessful;

        UpdateCurrentView(PageId.LoginView);
    }
}

LoginViewModel.cs登录视图模型.cs

public class LoginViewModel : BaseViewModel
{  
    public event EventHandler LoginSuccessful;
    private void OnLoginSuccessful() => this.LoginSuccessful?.Invoke(this, EventArgs.Empty);

    private async Task LoginUser(object para)
    {
        SqlConnector sqlConnector = new SqlConnector();
        if (ValidateForm() == false)
        {
            MessageBox.Show(ErrorMessages.ToString());
            return;
        }
        User user = await sqlConnector.FindUserByEmail(Email);
        if (user == null)
        {
            MessageBox.Show("Incorrect username or password");
            return;
        }
        IPasswordHasher passwordHasher = new PasswordHasher();
        var passwordResult = passwordHasher.VerifyHashedPassword(user.PasswordHash, Password);
        if (passwordResult == PasswordVerificationResult.Success)
        {
            MessageBox.Show("Login success.");
            OnLoginSuccessful();
        }
        else
        {
            MessageBox.Show("Incorrect username or password");
        }
        ClearProperties();
    }
}

Solution 2: Continuation Callback解决方案 2:继续回调

Or force the navigation view mode to provide a continuation callback via the constructor:或者强制导航视图模式通过构造函数提供延续回调:

MainViewModel.cs MainViewModel.cs

public class MainViewModel : BaseViewModel
{
    private Dictionary<PageId, BaseViewModel> Pages { get; set; }

    public MainViewModel()
    {
        this.Pages = new Dictionary<PageId, BaseViewModel>
        {
            { PageId.LoginView, new LoginViewModel(() => UpdateCurrentView(PageId.LoginView)) },
            { PageId.RegisterView, new RegisterViewModel() },
            { PageId.DashboardView, new DashboardViewModel() }
       };
    }

    private void UpdateCurrentView(object commandParameter)
    {
        if (commandParameter is PageId pageId
          && this.Pages.TryGetValue(pageId, out BaseViewModel nextPage))
        {
            this.CurrentView = nextPage;
        }
    }
}

LoginViewModel.cs登录视图模型.cs

public class LoginViewModel : BaseViewModel
{
    public Action LoginSuccessfulContinuation { get; set; }

    // Constructor
    public LoginViewModel(Action loginSuccessfulContinuation) => this.LoginSuccessfulContinuation = loginSuccessfulContinuation; 

    private async Task LoginUser(object para)
    {
        SqlConnector sqlConnector = new SqlConnector();
        if (ValidateForm() == false)
        {
            MessageBox.Show(ErrorMessages.ToString());
            return;
        }
        User user = await sqlConnector.FindUserByEmail(Email);
        if (user == null)
        {
            MessageBox.Show("Incorrect username or password");
            return;
        }
        IPasswordHasher passwordHasher = new PasswordHasher();
        var passwordResult = passwordHasher.VerifyHashedPassword(user.PasswordHash, Password);
        if (passwordResult == PasswordVerificationResult.Success)
        {
            MessageBox.Show("Login success.");
            this.LoginSuccessfulContinuation?.Invoke();
        }
        else
        {
            MessageBox.Show("Incorrect username or password");
        }
        ClearProperties();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我可以在这里使用ac#开关吗? - can I use a c# switch here? 在 c# windows 申请表中登录仪表板后如何获取用户名 - How I get the username after login in the dashboard in c# windows application form 如果在C#中成功登录,如何获取其他列值 - How to get other column value if login successfull in c# 如何防止在C#代码中包装WPF FlowDocument? - How can I prevent wrapping in a WPF FlowDocument in C# code? 如何从 C# 代码访问 wpf 中的 ResourceDictionary? - How can I access ResourceDictionary in wpf from C# code? I'm using Wpf C# and I have a couple of windows, how can I link code behind form one window to other code behind window - I'm using Wpf C# and I have a couple of windows, how can I link code behind form one window to other code behind window 成功消息后如何重定向登录页面 - How to redirect login page after successfull message 如何在C#wpf中获取登录用户的文档路径 - How to get login user's document path in C# wpf 不确定我在这里缺少什么? C#(30 天代码挑战;条件语句介绍) - Not sure what I'm missing here? C#(30 Days of Code Challenge; Intro to Conditional Statements) C#.Net Framework WPF:如何进行 POST 调用并保存登录 Baerer 密钥? - C# .Net Framework WPF: How can I do POST call and save login Baerer key?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM