常用命令

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之自定义委托命令的更多相关文章

  1. WPF之事件绑定命令

    目录 事件绑定意义 无参数的事件绑定 带EventArgs参数的事件绑定 使用事件绑定 扩展:基于InvokeCommandAction源码的实现(推荐) 参考资料 事件绑定意义 一般事件的处理程序都 ...

  2. 阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:9. 自定义委托事件方法

    文档目录: 说明 1. 连接阿里云物联网 2. IoT 客户端 3. 订阅Topic与响应Topic 4. 设备上报属性 4.1 上报位置信息 5. 设置设备属性 6. 设备事件上报 7. 服务调用 ...

  3. 示例:WPF中自定义MessageService应用DialogHost、Snackbar、NotifyIcon显示各种场景提示消息

    原文:示例:WPF中自定义MessageService应用DialogHost.Snackbar.NotifyIcon显示各种场景提示消息 一.目的:不同交互场景需要提示不同的消息,不同的消息需要用不 ...

  4. 示例:WPF中自定义StoryBoarService在代码中封装StoryBoard、Animation用于简化动画编写

    原文:示例:WPF中自定义StoryBoarService在代码中封装StoryBoard.Animation用于简化动画编写 一.目的:通过对StoryBoard和Animation的封装来简化动画 ...

  5. 自定义委托类型 - .Net自带委托类型

    委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递. 与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用. 一.自定义委托类型 1.语法结构:访问修 ...

  6. EventHandler委托与自定义委托

    http://blog.csdn.net/uuxyz/article/details/7175248 EventHandler委托与自定义委托 自定义委托: //1. public delegate ...

  7. WPF 之 自定义窗体标题栏

    在WPF中自定义窗体标题栏,首先需要将窗体的WindowStyle属性设置为None,隐藏掉WPF窗体的自带标题栏.然后可以在窗体内部自定义一个标题栏. 例如,标题栏如下: <WrapPanel ...

  8. 在WPF中自定义你的绘制(五)

    原文:在WPF中自定义你的绘制(五) 在WPF中自定义你的绘制(五)                                                                   ...

  9. 在WPF中自定义你的绘制(三)

    原文:在WPF中自定义你的绘制(三) 在WPF中自定义你的绘制(三)                                                                  ...

随机推荐

  1. celery 与 flask 实现异步任务调度

    Flask 定了2中上下文,来实现机遇线程\协程的,wsgi服务的请求(request.session)和存储(g,current_app )过程,通过栈来完成不同线程和协程的上下文切换,在与cele ...

  2. 如何使用excel制作查分系统

    在工作学习中,我们经常会遇到使用excel制作查分系统这样的问题.培根说过:读书足以恬情,足以博采,足以长才.因此,面对使用excel制作查分系统我们应该有努力探索的精神.书到用时方恨少,事非经过不知 ...

  3. (4)MySQL进阶篇SQL优化(常用SQL的优化)

    1.概述 前面我们介绍了MySQL中怎么样通过索引来优化查询.日常开发中,除了使用查询外,我们还会使用一些其他的常用SQL,比如 INSERT.GROUP BY等.对于这些SQL语句,我们该怎么样进行 ...

  4. Spring Native 项目,把 Spring 项目编译成原生程序!

    Spring Native 是什么 优点 缺点 原生镜像(native image)和常规 JVM 程序的区别 前置条件:GraalVM 支持的语言 关键特性 GraalVM 下的 Java 微服务 ...

  5. java例题_05 判断分数等级

    1 /*5 [程序 5 判断分数等级] 2 题目:利用条件运算符的嵌套来完成此题:学习成绩>=90 分的同学用 A 表示,60-89 分之间的用 B 表示,60 分以下的用 C 表示. 3 程序 ...

  6. 获取执行计划之Autotrace

    Autotrace 简介 AUTOTRACE是一项SQL*Plus功能,自动跟踪为SQL语句生成一个执行计划并且提供与该语句的处理有关的统计. AUTOTRACE的好处是您不必设置跟踪文件的格式,并且 ...

  7. 计划任务统一集中管理系统cronsun(替代crontab)

    一.背景 crontab 是 Linux 系统里面最简单易用的定时任务管理工具,相信绝大多数开发和运维都用到过,很多业务系统的定时任务都是通过 crontab 来定义的,时间长了后会发现存在很多问题: ...

  8. C#字符处理的性能问题

    1."+"拼接 +拼接会每次会导致新创建一个字符串,消耗内存.多个(10个以内)固定的字符连接可以使用"+"进行连接.编译器会做相应的优化会依据加号次数调用不同 ...

  9. OO_Unit1_表达式求导总结

    OO_Unit1_表达式求导总结   OO的第一单元主要是围绕表达式求导这一问题布置了3个子任务,并在程序的鲁棒性与模型的复杂度上逐渐升级,从而帮助我们更好地提升面向对象的编程能力.事实也证明,通过这 ...

  10. 记一次metasploitable2内网渗透之2049端口NFS漏洞

    0x01.NFS简介 NFS是基于UDP/IP协议的应用,其实现主要是采用远程过程调用RPC机制,RPC提供了一组与机器.操作系统以及低层传送协议无关的存取远程文件的操作.RPC采用了XDR的支持.X ...