这是一种设计模式
解耦的过程
M:model 数据模型
V: view 界面
VM: ViewModel 整合业务的过程
M的实例
public partial class MainWindow : Window
{
LoginModel loginModel;
public MainWindow()
{
InitializeComponent();
loginModel = new LoginModel();
// 将数据绑定的必要操作 loginModel里面有UserName和Password
this.DataContext = loginModel;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (loginModel.UserName == "wpf" && loginModel.Password == "666")
{
//弹出新的界面
Index index = new Index();
index.Show();
//隐藏当前界面
this.Hide();
}
else
{
//弹出一个警告框
MessageBox.Show("输入的用户名或密码不正确");
loginModel.UserName = "";
loginModel.Password = "";
}
}
}
//
//这里是如何将M提出来的
//
public class LoginModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handle = PropertyChanged;
if (handle != null)
{
handle(this, new PropertyChangedEventArgs(propertyName));
}
}
// 这里写法也固定,接收账号密码
private string _UserName;
public string UserName
{
get { return _UserName; }
set { _UserName = value; RaisePropertyChanged("UserName"); }
}
private string _Password;
public string Password
{
get { return _Password; }
set { _Password = value; RaisePropertyChanged("Password"); }
}
}
M和VM的分离(未完全版)
创建LoginModel(这是M)
public class LoginModel
{
// 这里写法也固定,接收账号密码
private string _UserName;
public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}
private string _Password;
public string Password
{
get { return _Password; }
set { _Password = value; }
}
}
创建LoginVM(这是VM)
internal class LoginVM:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handle = PropertyChanged;
if (handle != null)
{
handle(this, new PropertyChangedEventArgs(propertyName));
}
}
private LoginModel _LoginM;
public LoginModel LoginM
{
get {
if(_LoginM == null)
_LoginM = new LoginModel();
return _LoginM;
}
set {
_LoginM = value;
RaisePropertyChanged("LoginM");
}
}
}
主函数(这是V)
public partial class MainWindow : Window
{
LoginVM loginVm;
public MainWindow()
{
InitializeComponent();
loginVm = new LoginVM();
//这行代码,就是将绑定的loginVm中,所以在xmal中binding 后面直接是LoginVM里的成员
this.DataContext = loginVm;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (loginVm.LoginM.UserName == "wpf" && loginVm.LoginM.Password == "666")
{
//弹出新的界面
Index index = new Index();
index.Show();
//隐藏当前界面
this.Hide();
}
else
{
//弹出一个警告框
MessageBox.Show("输入的用户名或密码不正确");
loginVm.LoginM.UserName = "";
loginVm.LoginM.Password = "";
//只有这里的代码不能在v上改变
//此时的m是空,但是vm不是,所以重新将m的值赋予给vm
loginVm.LoginM = loginVm.LoginM;
}
}
}
xmal修改的地方
绑定发生变化
<TextBlock Text="用户名" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"/>
<TextBox Text="{Binding LoginM.UserName}" Grid.Row="0" Grid.Column="1" Margin="2"/>
<TextBlock Text="密码" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"/>
<TextBox Text="{Binding LoginM.Password}" Grid.Row="1" Grid.Column="1" Margin="2"/>
换一种写法
LoginModel没有变化
LoginVM将数据分别私有和暴露
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handle = PropertyChanged;
if (handle != null)
{
handle(this, new PropertyChangedEventArgs(propertyName));
}
}
//方法二:直接暴露UserName
private LoginModel _LoginM = new LoginModel();
public string UserName { get { return _LoginM.UserName; } set { _LoginM.UserName = value;RaisePropertyChanged("UserName"); } }
public string Password { get { return _LoginM.Password; } set { _LoginM.Password = value; RaisePropertyChanged("Password"); } }
V里面可以直接写,不同重新生成一次通知
private void Button_Click(object sender, RoutedEventArgs e)
{
if (loginVm.UserName == "wpf" && loginVm.Password == "666")
{
//弹出新的界面
Index index = new Index();
index.Show();
//隐藏当前界面
this.Hide();
}
else
{
//弹出一个警告框
MessageBox.Show("输入的用户名或密码不正确");
loginVm.UserName = "";
loginVm.Password = "";
}
}
xmal里修改为最初的样子
<TextBlock Text="用户名" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"/>
<TextBox Text="{Binding UserName}" Grid.Row="0" Grid.Column="1" Margin="2"/>
<TextBlock Text="密码" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"/>
<TextBox Text="{Binding Password}" Grid.Row="1" Grid.Column="1" Margin="2"/>
MVVM命令
创建一个类(用来绑定命令),直接代码复制就可以
public class RelayCommond:ICommand
{
// 命令是否能够执行
readonly Func<bool> _canExecute;
//命令需要执行的方法
readonly Action _execute;
public RelayCommond(Action action,Func<bool> canExecute)
{
_execute = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if(_canExecute == null)
{
return true;
}
return _canExecute();
}
public void Execute(object parameter)
{
_execute();
}
public event EventHandler CanExecuteChanged
{
add
{
if(_canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if(_canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
}
M不发生改变
public class LoginModel
{
// 这里写法也固定,接收账号密码
private string _UserName;
public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}
private string _Password;
public string Password
{
get { return _Password; }
set { _Password = value; }
}
}
VM增加绑定需要的方法
internal class LoginVM : INotifyPropertyChanged
{
private MainWindow _main;
public LoginVM(MainWindow main)
{
_main = main;
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handle = PropertyChanged;
if (handle != null)
{
handle(this, new PropertyChangedEventArgs(propertyName));
}
}
//方法二:直接暴露UserName
private LoginModel _LoginM = new LoginModel();
public string UserName { get { return _LoginM.UserName; } set { _LoginM.UserName = value;RaisePropertyChanged("UserName"); } }
public string Password { get { return _LoginM.Password; } set { _LoginM.Password = value; RaisePropertyChanged("Password"); } }
//登录方法
void LoginFunc()
{
if (UserName == "wpf" && Password == "666")
{
//弹出新的界面
Index index = new Index();
index.Show();
//隐藏当前界面
_main.Hide();
}
else
{
//弹出一个警告框
MessageBox.Show("输入的用户名或密码不正确");
UserName = "";
Password = "";
}
}
bool CanLoginExecute()
{
return true;
}
// 就是命令 等下绑定到登录按钮上
public ICommand LoginAction
{
get
{
return new RelayCommond(LoginFunc, CanLoginExecute);
}
}
}
V可以实现更简洁的代码
public MainWindow()
{
InitializeComponent();
//将实例传过去,不然在vm里面不能使用hide隐藏
this.DataContext = new LoginVM(this);
}
xmal绑定案例
<Button Grid.Row="3" Grid.ColumnSpan="2" Content="登录" Command="{Binding LoginAction}"/>