WPF之自定义委托命令
常用命令
WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类,还可以使用自定义命令。
RoutedCommand只负责跑腿,并不对命名目标做任何操作,实际操作没那么方便而且需要在后台实现相关的事件,可以参考WPF 命令。
自定义命令直接在命令目标上起作用,而不像RoutedCommand那样先在命令目标上激发出路由事件等外围控件捕捉到事件后再“翻过头来”对命令目标加以处理。
委托命令
实现一个DelegateCommand,代码如下:
using System;
using System.Windows.Input;
/// <summary>
/// 委托命令
/// </summary>
public class DelegateCommand : ICommand
{
private Action executeAction;
private Func<bool> canExecuteFunc;
/// <summary>
/// 当出现影响是否应执行该命令的更改时发生。
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// 构造函数,不指定canExecute委托时CanExecute方法默认返回true
/// </summary>
/// <param name="execute"></param>
/// <param name="canExecute"></param>
public DelegateCommand(Action execute, Func<bool> canExecute = null)
{
if (execute != null)
{
executeAction = execute;
canExecuteFunc = canExecute;
}
}
/// <summary>
/// 定义在调用此命令时要调用的方法。
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
if (executeAction != null && CanExecute(parameter))
{
executeAction();
}
}
/// <summary>
/// 定义确定此命令是否可在其当前状态下执行的方法。
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
if (canExecuteFunc == null)
{
return true;
}
return canExecuteFunc();
}
}
上面的代码使用了系统的CommandManager.RequerySuggested,如果ViewModel有继承绑定基类,可以在基类中监控属性值的变更并触发CanExecuteChanged以节省性能损耗。此时,添加如下代码:
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
委托命令(泛型)
为需要传参数的委托命令实现一个泛型版本,相当于直接使用object,泛型可以在编译期间检查类型错误。DelegateCommand<T>代码如下:
using System;
using System.Windows.Input;
/// <summary>
/// 委托命令——带泛型参数
/// </summary>
/// <typeparam name="T"></typeparam>
public class DelegateCommand<T> : ICommand
{
private Action<T> executeAction;
private Func<T, bool> canExecuteFunc;
/// <summary>
/// 当出现影响是否应执行该命令的更改时发生。
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// 构造函数,不指定canExecute委托时CanExecute方法默认返回true
/// </summary>
/// <param name="execute"></param>
/// <param name="canExecute"></param>
public DelegateCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
if (execute != null)
{
executeAction = execute;
canExecuteFunc = canExecute;
}
}
/// <summary>
/// 定义在调用此命令时要调用的方法。
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
if (executeAction != null && CanExecute(parameter))
{
executeAction(ChangeTo<T>(parameter));
}
}
/// <summary>
/// 定义确定此命令是否可在其当前状态下执行的方法。
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
if (canExecuteFunc == null)
{
return true;
}
return canExecuteFunc(ChangeTo<T>(parameter));
}
/// <summary>
/// object转为泛型类型,兼容数值、对象实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
private static T ChangeTo<T>(object obj)
{
T result = default(T);
if (obj != null)
{
try
{
result = (T)Convert.ChangeType(obj, typeof(T));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
return result;
}
}
泛型版本的类型转换比较麻烦,泛型参数需要考虑字符串、数值、对象实例等情况。参数尽量使用后台绑定的值,绑定更新过程可以将类型转换异常提前暴露出来,避免异常发生在命令执行过程中。
使用委托命令
创建一个MainViewModel,代码如下:
class MainViewModel
{
public bool CanExecute { get; set; }
public int Param { get; set; }
public DelegateCommand NormalCommand { get; }
public DelegateCommand<int> ParamCommand { get; }
public MainViewModel()
{
NormalCommand = new DelegateCommand(() => { MessageBox.Show("无参命令执行成功"); }, () => CanExecute);
ParamCommand = new DelegateCommand<int>(i => { MessageBox.Show("参数命令执行成功:" + i); }, i => CanExecute);
}
}
界面的XAML代码如下:
<StackPanel>
<CheckBox Content = "命令开关" IsChecked="{Binding CanExecute}"/>
<Label Content = "命令参数:" />
< TextBox Text="{Binding Param}"/>
<Button Content = "无参数命令" Command="{Binding NormalCommand}"/>
<Button Content = "有参数命令" Command="{Binding ParamCommand}" CommandParameter="{Binding Param}" />
</StackPanel>
在后台代码中添加DataContext:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
运行程序,效果如下:


参考资料
MVVM模式解析和在WPF中的实现(三)命令绑定
Prism.Core/Commands
WPF之自定义委托命令的更多相关文章
- WPF之事件绑定命令
目录 事件绑定意义 无参数的事件绑定 带EventArgs参数的事件绑定 使用事件绑定 扩展:基于InvokeCommandAction源码的实现(推荐) 参考资料 事件绑定意义 一般事件的处理程序都 ...
- 阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:9. 自定义委托事件方法
文档目录: 说明 1. 连接阿里云物联网 2. IoT 客户端 3. 订阅Topic与响应Topic 4. 设备上报属性 4.1 上报位置信息 5. 设置设备属性 6. 设备事件上报 7. 服务调用 ...
- 示例:WPF中自定义MessageService应用DialogHost、Snackbar、NotifyIcon显示各种场景提示消息
原文:示例:WPF中自定义MessageService应用DialogHost.Snackbar.NotifyIcon显示各种场景提示消息 一.目的:不同交互场景需要提示不同的消息,不同的消息需要用不 ...
- 示例:WPF中自定义StoryBoarService在代码中封装StoryBoard、Animation用于简化动画编写
原文:示例:WPF中自定义StoryBoarService在代码中封装StoryBoard.Animation用于简化动画编写 一.目的:通过对StoryBoard和Animation的封装来简化动画 ...
- 自定义委托类型 - .Net自带委托类型
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递. 与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用. 一.自定义委托类型 1.语法结构:访问修 ...
- EventHandler委托与自定义委托
http://blog.csdn.net/uuxyz/article/details/7175248 EventHandler委托与自定义委托 自定义委托: //1. public delegate ...
- WPF 之 自定义窗体标题栏
在WPF中自定义窗体标题栏,首先需要将窗体的WindowStyle属性设置为None,隐藏掉WPF窗体的自带标题栏.然后可以在窗体内部自定义一个标题栏. 例如,标题栏如下: <WrapPanel ...
- 在WPF中自定义你的绘制(五)
原文:在WPF中自定义你的绘制(五) 在WPF中自定义你的绘制(五) ...
- 在WPF中自定义你的绘制(三)
原文:在WPF中自定义你的绘制(三) 在WPF中自定义你的绘制(三) ...
随机推荐
- Java工程师核心书单推荐
随便打开一个招聘网站,看看对高级Java工程师的技能要求. 抛开其它的经验能力等等,单纯从技术,或者说知识上来讲,可以发现一些共通的地方. Java基础 计算机基础 数据库,SQL/NoSQL 常用开 ...
- beego 框架用的页面样式模板
https://themequarry.com/category/free 页面样式
- golang 二维平面求多重遮挡三角形总面积
解决问题描述:二维平面有很多三角形错落,可能会相互叠加落在一起,也可能互相远离.目标求出这些三角形的总占地面积. 我最开始想的解决方案是用总面积-总重叠面积 = 总占地面积.后来实现起来发现当面临多次 ...
- “/”应用程序中的服务器错误。||分析器错误消息: 未能加载类型“WebApplication1._Default”
环境VS2008 无法运行WEB项目,Winfrom程序OK. 新创建的WEB项目直接运行报下图错误. 尝试多种方法: 1,重新生成项目,运行.(失败) 2,重装VS2008(默认.完全.自定义)安装 ...
- 攻防世界 reverse tt3441810
tt3441810 tinyctf-2014 附件给了一堆数据,将十六进制数据部分提取出来, flag应该隐藏在里面,(这算啥子re,) 保留可显示字符,然后去除填充字符(找规律 0.0) 处理脚本: ...
- Java系列教程-Spring 教程目录
Spring 教程目录 可参考MyBatis的官方文档也比较清楚 https://mybatis.org/mybatis-3/zh/getting-started.html 代码 目录 https:/ ...
- 【linux】驱动-6-总线-设备-驱动
目录 前言 6. 总线-设备-驱动 6.1 概念 6.2 工作原理 6.3 总线 6.3.1 总线介绍 6.3.2 注册总线 6.4 设备 6.4.1 设备介绍 6.4.2 设备注册.注销 6.5 驱 ...
- 前端开发面试题 — html篇
正值跳槽的金三银四月,在四月的中旬之际,博主为大家整理了几篇前端面试题,希望不会太迟 1.Doctype作用?标准模式与兼容模式各有什么区别? (1)<!DOCTYPE> 声明位于HTML ...
- kali 2019-4中文乱码解决方法
1.更换阿里源 编辑源,apt-get update && apt-get upgrade && apt-get clean ,更新好源和更新软件 #阿里云deb ht ...
- java面试一日一题:讲对mysql的MVCC的理解
问题:请讲下对mysql中MVCC的理解 分析:这个问题要回答的是对MVCC的理解,以及MVCC解决了什么问题这几个方面入手. 回答要点: 主要从以下几点去考虑, 1.什么是MVCC? 2.MVCC用 ...