WPF使用MVVM(二)-命令绑定
WPF使用MVVM(二)-命令绑定
上一节已经介绍了WPF的属性绑定,这使得我们只需要指定界面的DataContext,然后就可以让界面绑定我们的属性数据呢。
但是上一节还遗留了一个问题就是我们的按钮的Click方法,依然是写在界面的后台中的,现在我们希望将按钮的Click方法也采用绑定的形式。
原先是这样的:
<Button
Grid.Row="3"
Grid.ColumnSpan="2"
Margin="20"
Click="Button_Click"
Content="更新一下信息"
FontSize="30"
FontWeight="Bold" />
希望变成这样:
<Button
Grid.Row="3"
Grid.ColumnSpan="2"
Margin="20"
Click="{Binding ClickAction}"
Content="更新一下信息"
FontSize="30"
FontWeight="Bold" />
让我们的MainWindowVM(ViewModel)也提供一个方法,让我们绑定一下,这样界面的数据和按钮的点击处理逻辑,都放到了桥梁ViewModel中了,界面看起来也很清爽。
Command
WPF呢,为了让我们用MVVM的形式替换按钮的点击行为,给我们提供了一个Command的属性,让我们也可以像绑定属性的方式,来绑定我们的点击方法,具体的写法如下:
<Button
Grid.Row="3"
Grid.ColumnSpan="2"
Margin="20"
Command="{Binding ClickAction}"
Content="更新一下信息"
FontSize="30"
FontWeight="Bold" />
之前写的Button_Click方法也可以直接删除了。
注意:Command属性仅仅作为Click行为的绑定,其他行为,如鼠标移入、移出。。。等行为,要使用另外的MVVM方式进行绑定。(本文只介绍点击行为,后续介绍其他行为的MVVM实现)
添加ClickAction的实现
上面我们也删除了Button_Click方法,并且还给Button按钮的Command属性绑定了一个方法叫做ClickAction,接下来我们就要在MainWindowVM(ViewModel)中去添加这个方法。
要实现绑定的方法ClickAction,就需要用到ICommand接口,需要我们自己创建类型去实现接口的CanExecute、Execute、CanExecuteChanged,下面直接贴一下实现接口的代码,需要新建一个类,名字我们取RelayCommand:
public class RelayCommand : ICommand
{
/// <summary>
/// 命令能否执行
/// </summary>
readonly Func<bool> _canExecute;
/// <summary>
/// 命令执行的方法
/// </summary>
readonly Action _execute;
/// <summary>
/// 命令的构造函数
/// </summary>
/// <param name="action">命令需执行的方法</param>
/// <param name="canExecute">命令是否可以执行的方法</param>
public RelayCommand(Action action, Func<bool> canExecute)
{
_execute = action;
_canExecute = canExecute;
}
/// <summary>
/// 判断命令是否可以执行
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(Object parameter)
{
if (_canExecute == null)
return true;
return _canExecute();
}
/// <summary>
/// 执行命令
/// </summary>
/// <param name="parameter"></param>
public void Execute(Object parameter)
{
_execute();
}
/// <summary>
/// 事件追加、移除
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
}
创建这个类,就是为了在使用命令的时候, 创建一条命令出来用于绑定,这个类型接收两个参数,一个是命令执行的方法,另一个是有返回值的方法, 这个返回值bool用来确定,该条命令是否可以执行,如果命令不能被执行,则按钮的IsEnabled就被会设置成不可点击,下面我们来挨个看下效果
MainWindowVM中创建一个命令
刚才我们已经做好了创建命令的准备工作,下面直接创建一个命令,并给这个命令指定一个方法即可。
在MainWindowVM添加如下代码:
/// <summary>
/// 命令要执行的方法
/// </summary>
void UpdateNameExecute()
{
EmployeeM.Name = "王明(原属性修改)";
EmployeeM = EmployeeM;
}
/// <summary>
/// 命令是否可以执行
/// </summary>
/// <returns></returns>
bool CanUpdateNameExecute()
{
return true;
}
/// <summary>
/// 创建新命令
/// </summary>
public ICommand ClickAction
{
get
{
return new RelayCommand(UpdateNameExecute, CanUpdateNameExecute);
}
}
注意,创建这个新的命令的名字需要和我们界面按钮Command中绑定的名字一致,叫ClickAction。
这时候我们运行一下程序,点击按钮,可以看到命令是可以生效的。
此时我们做一个小小的改动,我们将是否可以执行的方法返回为False:
/// <summary>
/// 命令是否可以执行
/// </summary>
/// <returns></returns>
bool CanUpdateNameExecute()
{
return false;
}
再次运行能够看到,界面中按钮已经是不可点击的状态了!
所以我们绑定的这个命令是否可以执行,是直接影响到按钮能否被点击的!这个值会直接作用在按钮的IsEnabled上。
命令带点私货-参数
上面的命令就是纯命令,啥参数都没带上,有时候希望执行命令的时候,希望能够传个参数,那就需要改造一下了!
采用泛型的形式,给Action加点料,重新贴一下RelayCommand的代码:
public class RelayCommand<T> : ICommand
{
/// <summary>
/// 命令能否执行
/// </summary>
readonly Func<bool> _canExecute;
/// <summary>
/// 命令执行的方法
/// </summary>
readonly Action<T> _execute;
/// <summary>
/// 命令的构造函数
/// </summary>
/// <param name="action">命令需执行的方法</param>
/// <param name="canExecute">命令是否可以执行的方法</param>
public RelayCommand(Action<T> action, Func<bool> canExecute)
{
_execute = action;
_canExecute = canExecute;
}
/// <summary>
/// 判断命令是否可以执行
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(Object parameter)
{
if (_canExecute == null)
return true;
return _canExecute();
}
/// <summary>
/// 执行命令
/// </summary>
/// <param name="parameter"></param>
public void Execute(Object parameter)
{
_execute((T)parameter);
}
/// <summary>
/// 事件追加、移除
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
}
在MainWindowVM(ViewModel)中创建的命令和给到的方法也要有点小变化:
/// <summary>
/// 命令要执行的方法
/// </summary>
void UpdateNameExecute(object sender)
{
EmployeeM.Name = "王明(原属性修改)";
EmployeeM = EmployeeM;
}
/// <summary>
/// 命令是否可以执行
/// </summary>
/// <returns></returns>
bool CanUpdateNameExecute()
{
return true;
}
/// <summary>
/// 创建新命令
/// </summary>
public ICommand ClickAction
{
get
{
return new RelayCommand<object>(UpdateNameExecute, CanUpdateNameExecute);
}
}
参数从哪里传呢, 当然是我们的界面传了,通过按钮的CommandParameter属性来传,这里我们将按钮自己传过去!
<Button
Grid.Row="3"
Grid.ColumnSpan="2"
Margin="20"
Command="{Binding ClickAction}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"
Content="更新一下信息"
FontSize="30"
FontWeight="Bold" />
运行断点看一下,能够看到按钮自身已经当作参数传入了:
下一节说一下事件的绑定,让其他事件,如MouseEnter、MouseLeave也能够像按钮的Command一样。
WPF使用MVVM(二)-命令绑定的更多相关文章
- 【我们一起写框架】MVVM的WPF框架(二)—绑定
MVVM的特点之一是实现数据同步,即,前台页面修改了数据,后台的数据会同步更新. 上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体. 那么现在就要开始实现数据同 ...
- WPF——数据绑定(二)绑定方法—绑定本地对象
注意:本人初学WPF,文中表达或技术性问题请勿见怪,欢迎指正,谢谢 标记拓展语法:绑定到本地对象 什么是绑定到本地对象,我个人理解就是实现UI层上两个或多个控件的相互关联,一个控件的状态改变,导致另一 ...
- 将命令绑定到事件中(WPF)
绑定到指定名称控件的——>指定属性上 <i:Interaction.Triggers> <i:EventTrigger E ...
- WPF中MVVM模式下控件自有的事件绑定
1.原因 在WPF中单纯的命令绑定往往不能满足覆盖所有的事件,例如ComboBox的SelectionChanged事件,DataGrid的SelectionChanged事件等等,这时就可以用事件绑 ...
- MVVM模式解析和在WPF中的实现(三)命令绑定
MVVM模式解析和在WPF中的实现(三) 命令绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...
- WPF采用MVVM模式(绑定:纯前台、命令:触发器绑定命令)
MVVM绑定 view-viewModel-model,模型介绍省略,就是创建类,添加字段封装属性.注:控件的绑定只能绑定到属性上,不能绑定到字段上: 接下来就是代码 (view): <Wind ...
- WPF中的命令与命令绑定(二)
原文:WPF中的命令与命令绑定(二) WPF中的命令与命令绑定(二) 周银辉在WPF中,命令(Commandi ...
- WPF中的命令与命令绑定导航
1.WPF中的命令与命令绑定(一) (引入命令) 2.WPF中的命令与命令绑定(二)(详细介绍命令和命令绑定)
- WPF系列教程——(二)使用Prism实现MVVM设计模式 - 简书
原文:WPF系列教程--(二)使用Prism实现MVVM设计模式 - 简书 本文假设你已经知道MVVM设计模式是什么,所以直接进入正题,今天我们就用Prism来实现WPF的MVVM设计模式,百度上关于 ...
随机推荐
- 使用批处理文件(.bat)启动多个CMD窗口并执行命令
由于每次启动本机的kafka都需要打开2个cmd窗口,分别启动zookeeper服务和kafka服务,操作相对繁琐,于是想起了批处理来帮忙一键启动. 在桌面新建一个txt文件,改后缀名为.bat,并加 ...
- JAVA开发 环境基础 IDEA 常用快捷键
java 源代码运行必须先用javac编译生成字节码文件 XXX.class运行 java XXX 进行运行 环境变量classpath:已编译的字节码文件搜索路径--临时配置: set classp ...
- Python pyecharts绘制折线图
一.pyecharts绘制折线图line.add()方法简介 line.add()方法简介 add(name,x_axis,y_axis,is_symbol_show=True, is_smooth= ...
- c++基础之虚函数表指针和虚函数表创建时机
虚函数表指针 虚函数表指针随对象走,它发生在对象运行期,当对象创建的时候,虚函数表表指针位于该对象所在内存的最前面. 使用虚函数时,虚函数表指针指向虚函数表中的函数地址即可实现多态. 虚函数表 虚函数 ...
- java源码——计算不同图形的周长和面积
计算任意三角形,正方形,正五边形,圆形的周长和面积. 利用类的继承实现. 将计算结果进行输出. 不多说,贴码. Contants.java 常量存储类 <pre name="code& ...
- 【LeetCode】723. Candy Crush 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力 日期 题目地址:https://leetcode ...
- 【LeetCode】697. Degree of an Array 解题报告
[LeetCode]697. Degree of an Array 解题报告 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/degree- ...
- Docker&K8S学习笔记(一)—— Docker安装
最近一年在工作上经常使用Docker与K8S,除了利用其打镜像,部署服务外,还基于Docker与K8S开发了一套CICD流水线平台,为了加深相关知识点的理解,所以从今天开始会定期更新学习笔记,本套学习 ...
- Hexo添加Live2D看板娘+模型预览
文章目录 添加和注意事项 模型预览 live2d-widget-model-chitose live2d-widget-model-epsilon2_1 live2d-widget-model-gf ...
- 【Java】质数判断
static boolean isPrime(int n) { if(n<=1) { return false; } if(n==2||n==3) { return true; } if(n%6 ...