MVVM复习
MVVM结构
- 用户-->界面,双向=》用户将数据输入给界面,操作施加给界面==》界面将数据和消息反馈给用户
- View和ViewModel交互主要依靠两种属性
- 数据属性=》双向==》数据依靠数据属性来回传递,
- 命令属性=》单向==》View -->ViewModel,永远只是把操作从界面传送到ViewModel
- ViewModel和Model、Service的交互都是双向的
数据属性基类NotificationObject
-
创建ViewsModels的基类NotificationObject具有通知能力的一个对象,派生自INotifyPropertyChanged
-
为什么需要这个对象:因为ViewsModel 和View交互,需要把自己的变化通知给View,就是靠WPF的DataBinding来通知,当一个值变化以后,通过某种机制通知Binding,Binding再把数据传输到View上,ViewsModel通知Binding,请你把我的数据传输到View上。
-
如何实现通知:通过一个事件,继承INotifyPropertyChanged接口,在派生类中实现接口成员(PropertyChanged事件)
-
如果某一个对象的属性借助DataBinding关联到了界面上的某个元素上,如果ViewModel上的某个属性借助DataBinding关联到View上的某个控件,当这个值变化的时候,实际上Binding就是在监听着PropertyChanged这个事件有没有发生,一旦发生,他就把变化后的值送到界面上去。
//具备通知能力 实现对应事件
class NotificationObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//对事件进行简单封装
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
//告诉Binding那个属性的值发生了改变
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
命令属性基类DelegateComman
-
创建DelegateCommand类,派生自ICommand
-
实现对应的三个成员:
- CanExecute,能不能做?用来帮助命令的呼叫者,判断这个命令能不能执行
- EventHandler,执行的状态!当这个命令能不能执行状态发生改变时,通知命令的调用者,告诉他状态
- Execute,做什么事?最为重要的是这个命令,当命令执行的时候,做什么事情
-
声明一个Action
-
声明一个Func<object,bool> CanExecuteFunc委托,CanExecuteFunc,当CanExecute ,return true就是说如果我们忽略了检查这个CanExecute的话,就永远都可以执行。
class DelegateCommand : ICommand
{
//用来帮助命令的呼叫者,判断这个命令能不能执行
public bool CanExecute(object parameter)
{
if (this.CanExecuteFunc == null)
{
return true;
}
this.CanExecuteFunc(parameter);
return false;
}
//当命令能不能执行状态发生改变时,通知命令的调用者,告诉他状态
public event EventHandler CanExecuteChanged;
//当命令执行时,做什么事情
public void Execute(object parameter)
{
if (this.ExeuteActio == null)
{
return;
}
this.ExeuteActio(parameter);
}
//声明一个Action的委托,当Execute执行的时候,做一件事情
public Action<object> ExeuteActio { get; set; }
public Func<object,bool> CanExecuteFunc { get; set;}
}
调用案例
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Text;
using 小案例.Commands;
namespace 小案例.ViewModels
{
class MainWindowViewModel:NotificationObject
{
//数据属性
private double input1;
public double Input1
{
get { return input1; }
set{
input1 = value;
this.RaisePropertyChanged("Input1");
}
}
private double input2;
public double Input2
{
get { return input2; }
set {
input2 = value;
this.RaisePropertyChanged("Input2"); }
}
private double result;
public double Result
{
get { return result; }
set { result = value;
this.RaisePropertyChanged("Result");
}
}
//命令属性
public DelegateCommand AddCommand { get; set; }
public DelegateCommand SaveCommand { get; set; }
private void Add(Object parameter)
{
this.Result = this.Input1 + this.Input2;
}
private void Save(object parameter)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.ShowDialog();
}
//进行关联
public MainWindowViewModel()
{
this.AddCommand = new DelegateCommand();
this.AddCommand.ExeuteActio = new Action<object>(this.Add);
this.SaveCommand = new DelegateCommand();
this.SaveCommand.ExeuteActio = new Action<object>(this.Save);
}
}
}
//UI
<TextBox x:Name="tb1" Grid.Row="0" Background="LightBlue" FontSize="24" Margin="4" Text="{Binding Input1}"/>
<TextBox x:Name="tb2" Grid.Row="1" Background="LightBlue" FontSize="24" Margin="4" Text="{Binding Input2}"/>
<TextBox x:Name="tb3" Grid.Row="2" Background="LightBlue" FontSize="24" Margin="4" Text="{Binding Result}"/>
<Button x:Name="addButton" Grid.Row="3" Content="计算" Width="120" Height="80" FontSize="27" Background="Lavender" Command="{Binding AddCommand}"/>
//MainWindow
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}