繁体   English   中英

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

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

这是我的 xaml 代码。 我想在成功登录尝试后更新当前视图。

<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();
        }
    }
}

这里当用户登录时它应该更新当前视图,它正在执行命令我也在命令参数中获取值并且它还在 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;
    }

这不起作用,因为您在成功登录后创建了MainViewModel的新实例。 这不是您视图的DataContext实例。

您可以传递对MainViewModel实例的引用,例如,通过构造函数传递给LoginViewModel 但是由于LoginViewModel并不真正依赖于MainViewModel ,所以我不会那样做。
相反,我建议使用以下两种解决方案之一。 通常,您的页面视图模型不应该关心内容导航。 这应该是父导航视图 model 的唯一责任,它已经知道导航详细信息,如当前页面或下一页等。两个示例都遵循这个想法。

另请注意,由于每次用户导航时您都在创建新的页面视图模型,因此您将丢失所有内容。 返回上一页将显示一个空白的初始页面。 此外, switch在可扩展性方面非常糟糕。 添加新页面不是很好,并且会破坏您的UpdateCurrentView方法。

我重构了您的代码以展示一种简单的方法来保持页面导航的简单性和可扩展性。 这只是一些小改动:添加一个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>

方案一: LoginSuccessful事件

您可以公开一个LoginSuccessful事件,导航视图 model 可以监听:

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);
    }
}

登录视图模型.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();
    }
}

解决方案 2:继续回调

或者强制导航视图模式通过构造函数提供延续回调:

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;
        }
    }
}

登录视图模型.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM