簡體   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