初次接触的新名词--MVVM,听着好高大上的名字。经查阅,发现也没有想象中的那么难。
mvvm【模型-视图-视图模型(Model-View-ViewModel)】是由MVP【模型-视图-表现类(Model-View-Presenter)】发展而来,MVP则是由MVC【模型-视图-控制器(ModelView Controller)】发展而来。由此看来,mvvm其实也不是新知识。
View:是UI界面,就是用wpf的xaml实现的界面,负责与用户交互,接收用户输入,把数据展现给用户。
ViewModel:一个C#类,负责收集需要绑定的数据和命令,实现View和Model之间的信息转换,处理UI逻辑。
Model:就是系统中的对象,可包含属性和行为。
本次要做的Demo是计算两个数之和。
简单的界面如图所示:
Xaml代码:
<span style="font-family:KaiTi_GB2312;font-size:24px;"><Window x:Class="MVVM.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="656"> <Grid Width="624"> <TextBox Height="23" HorizontalAlignment="Left" Margin="41,90,0,0" Name="txtNum1" VerticalAlignment="Top" Width="120" Text="{Binding Num1}"/> <TextBox Height="25" HorizontalAlignment="Left" Margin="195,88,0,0" Name="txtNum2" VerticalAlignment="Top" Width="120" Text="{Binding Num2}"/> <Label Content="+" Height="28" HorizontalAlignment="Left" Margin="167,88,0,0" Name="lable1" VerticalAlignment="Top"/> <TextBox Height="25" HorizontalAlignment="Left" Margin="364,88,0,0" Name="txtResult" VerticalAlignment="Top" Width="120" Text="{Binding Result}"/> <Button Content="=" Height="23" HorizontalAlignment="Left" Margin="328,90,0,0" Name="btnEqual" VerticalAlignment="Top" Width="28" Command="{Binding CaculateCommand}"/> <Button Content="Clear" Height="26" HorizontalAlignment="Left" Margin="501,88,0,0" Name="btnClear" VerticalAlignment="Top" Width="45" Command="{Binding ClearCommand}"/> </Grid> </Window> </span>
此处代码的重点在于Binding,用绑定来实现和后台的交互。这样,若后台代码修改后,只要绑定的名称不变,就不会影响到界面。
Xaml的后台cs:
<span style="font-family:KaiTi_GB2312;font-size:24px;">/// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { //构造方法 public MainWindow() { InitializeComponent(); //将View的DataContext设为CaculatorViewModel实例 this.DataContext = new CaculatorViewModel(); //ViewModel通过View类的DataContext属性绑定到View } } </span>View通过DataContext实现与ViewModel的交互。
Model层代码:
<span style="font-family:KaiTi_GB2312;font-size:24px;">//Model层的类 public class CaculatorModel { public int Num1 { get; set; } //参数一 public int Num2 { get; set; } //参数二 public int Result { get; set; } //计算结果 } </span>
ICommand类型的基类,用来实现View和ViewModel之间Command的绑定。
<span style="font-family:KaiTi_GB2312;font-size:24px;">//ICommand类型的基类DelegateCommand //目的是绑定命令属性。这个类的作用是实现了ICommand接口,WPF中实现了ICommand接口的类,才能作为命令绑定到UI。 public class DelegateCommand:ICommand { // private Action<object> executeCommand; public Action<object> ExecuteCommand { get { return executeCommand; } set { executeCommand = value; } } // private Func<object, bool> canExecuteCommand; public Func<object, bool> CanExecuteCommand { get { return canExecuteCommand; } set { canExecuteCommand = value; } } // public event EventHandler CanExecuteChanged; //是继承ICommand必须实现的方法,表示Command调用时判断是否能执行 public bool CanExecute(object parameter) { if (CanExecuteCommand!=null) { return this.CanExecuteCommand(parameter); } else { return true; } } //是继承ICommand必须实现的方法,表示Command调用时具体执行逻辑 public void Execute(object parameter) { if (this.ExecuteCommand!=null) { this.ExecuteCommand(parameter); } } public void RaiseCanExecuteChanged() { if (CanExecuteCommand!=null) { CanExecuteChanged(this, EventArgs.Empty); } } public DelegateCommand(Action<object> executeCommand, Func<object, bool> canExecuteCommand) { this.executeCommand = executeCommand; this.canExecuteCommand = canExecuteCommand; } }</span>
ViewModel:
<span style="font-family:KaiTi_GB2312;font-size:24px;">//ViewModel的基类 public class ViewModelBase:INotifyPropertyChanged { //ViewModelBase实现了接口INotifyPropertyChanged, 在该接口中有一个PropertyChanged事件, 当ViewModel中的Property改变时,允许触发PropertyChanged事件,继而重新绑定数据到UI上。 //目的是绑定数据属性。这个类的作用是实现了INotifyPropertyChanged接口。WPF中类要实现这个接口,其属性成员才具备通知UI的能力 public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string propertyName) { if (this.PropertyChanged!=null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }</span>所有的具体的ViewModel类都要继承ViewModel基类。
<span style="font-family:KaiTi_GB2312;font-size:24px;">//ViewModel具体的实现 public class CaculatorViewModel : ViewModelBase { #region Fields 字段 private int num1; private int num2; private int result; private CaculatorModel model; #endregion #region Properties 属性 public int Num1 { get { return num1; } set { num1 = value; this.RaisePropertyChanged("Num1"); } } public int Num2 { get { return num2; } set { num2 = value; this.RaisePropertyChanged("Num2"); } } public int Result { get { return result; } set { result = value; this.RaisePropertyChanged("Result"); } } #endregion #region Commands 命令 public ICommand CaculateCommand { get; set; } public ICommand ClearCommand { get; set; } #endregion #region Methods 方法 //相加的方法 public void Add(object param) { Result = Num1 + Num2; } //清空的方法 public void Clear(object param) { Result = 0; Num1 = 0; Num2 = 0; } //初始化Model数据 public void InitilizeModelData() { var model = new CaculatorModel() { Num1 = 1, Num2 = 1, Result = 2 }; Num1 = model.Num1; Num2 = model.Num2; Result = model.Result; } //构造方法 public CaculatorViewModel() { CaculateCommand = new DelegateCommand(Add, null); //CaculateCommand = new DelegateCommand(Reduce, null); ClearCommand = new DelegateCommand(Clear, null); InitilizeModelData(); } //相减的方法 //public void Reduce(object param) //{ // Result = Num1 - Num2; //} #endregion }</span>若用户想将加法运算改为减法运算,我们只需要在ViewModel中添加一个减法运算的方法,在View中重新绑定一下就OK了。