WPF MVVM从入门到精通2:实现一个登录窗口

 

WPF MVVM从入门到精通1:MVVM模式简介

WPF MVVM从入门到精通2:实现一个登录窗口

WPF MVVM从入门到精通3:数据绑定

WPF MVVM从入门到精通4:命令和事件

WPF MVVM从入门到精通5:PasswordBox的绑定

WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定

WPF MVVM从入门到精通7:关闭窗口和打开新窗口

WPF MVVM从入门到精通8:数据验证

完整示例代码下载LoginDemo

 

我们究竟要做一个怎样的东西呢?直接上图:

这看起来比较简单,但把这个登录窗口做完,MVVM的入门就基本完成了。(为什么登录界面要选择性别这么奇怪?无非是因为RadioButton的绑定也是一个课题)

很多教程都是举一个小例子,让人刚开始接触的时候不知道如何在项目中使用。我这里从一个项目的开发角度简单说说。

首先,这个窗口只是一个项目众多窗口中的其中一个。为简单起见,我们把项目文件安排如下:

我们新建了一个ViewModel文件夹,里面按View的内容分文件夹,然后每个文件夹里面包含了Model类和ViewModel类。同时,ViewModel文件夹里有一个Common文件夹,存放一些ViewModel需要共用的类。当然,如果读者有更好的想法,完全没必要按这个模式去做。

项目开始,我们不急着写代码,而是研究一下,在View里面都包含了哪些数据。我列了一个表格:

中文名类型英文名
用户名stringUserName
密码stringPassword
性别intGender
窗口初始化View->ViewModelWndInit
登录事件View->ViewModelLoginClick
关闭行为ViewModel->ViewToClose
打开新窗口ViewModel->ViewOpenWnd

前三项是显而易见的,后面四项可能我们并不认为是一种数据。但在MVVM模式下,狭义的数据、事件、行为都变成了可以绑定的一种元素,也可以说是数据。

我们在前面提过,View和ViewModel改变状态时,都是通过类似广播的方式去做的。它们不会传递对象,而只会传递一个名称。所以,为了可以让程序员和美工分头行事,在命名方面,我们应该一开始就固定下来。

现在,我们可以开始开发Model层了。Model层的代码如下:

namespace LoginDemo.ViewModel.Login
{
    /// <summary>
    /// 登录窗口Model
    /// </summary>
    public class LoginModel
    {
        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// 密码
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// 性别
        /// </summary>
        public int Gender { get; set; }
    }
}

Model层的代码就是这样,非常单纯,也没有什么新的知识。虽然我们后面会实现各种交互的逻辑,但Model层的代码已经不会改变了。

  • 20
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,以下是一个简单的WPF MVVM登录DEMO的代码示例: XAML代码: ``` <Window x:Class="LoginDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Login Demo" Height="250" Width="400"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="Username:" Margin="10"/> <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Username}" Margin="10"/> <Label Grid.Row="1" Grid.Column="0" Content="Password:" Margin="10"/> <PasswordBox Grid.Row="1" Grid.Column="1" Password="{Binding Password}" Margin="10"/> <Button Grid.Row="2" Grid.Column="1" Content="Login" Command="{Binding LoginCommand}" Margin="10"/> <TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding ErrorMessage}" Foreground="Red" Margin="10"/> <CheckBox Grid.Row="4" Grid.Column="1" Content="Remember me" IsChecked="{Binding RememberMe}" Margin="10"/> </Grid> </Window> ``` ViewModel代码: ``` using System; using System.ComponentModel; using System.Windows; using System.Windows.Input; namespace LoginDemo { public class LoginViewModel : INotifyPropertyChanged { private string _username; private string _password; private bool _rememberMe; private string _errorMessage; public string Username { get { return _username; } set { _username = value; OnPropertyChanged("Username"); } } public string Password { get { return _password; } set { _password = value; OnPropertyChanged("Password"); } } public bool RememberMe { get { return _rememberMe; } set { _rememberMe = value; OnPropertyChanged("RememberMe"); } } public string ErrorMessage { get { return _errorMessage; } set { _errorMessage = value; OnPropertyChanged("ErrorMessage"); } } public ICommand LoginCommand { get; set; } public LoginViewModel() { LoginCommand = new RelayCommand(Login); } private void Login(object parameter) { if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password)) { ErrorMessage = "Please enter both username and password."; } else if (Username == "admin" && Password == "password") { ErrorMessage = ""; MessageBox.Show("Login successful!"); } else { ErrorMessage = "Invalid username or password."; } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } ``` 其中,RelayCommand是一个自定义的ICommand实现,用于绑定按钮的Command属性,代码如下: ``` using System; using System.Windows.Input; namespace LoginDemo { public class RelayCommand : ICommand { private readonly Action<object> _execute; private readonly Predicate<object> _canExecute; public RelayCommand(Action<object> execute, Predicate<object> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute?.Invoke(parameter) ?? true; } public void Execute(object parameter) { _execute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } } } ``` 在MainWindow的构造函数中,将ViewModel与View绑定: ``` public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new LoginViewModel(); } } ``` 这样,就完成了一个简单的WPF MVVM登录DEMO。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值