WPF入门(3)——命令
命令是ICommand类型的属性,binding到控件上,用于代替事件,个人认为事件也很好,命令只是轻度解耦前后端。
闲话少说,上代码,示例是ScreenToGif的源代码中的一个命令:
public ICommand OpenOptions
{
get
{
return new RelayCommand
{
CanExecutePredicate = a => true, //TODO: Always let this window opens or check if there's any other recorder active?
ExecuteAction = a =>
{
var options = Application.Current.Windows.OfType<Options>().FirstOrDefault();
var tab = a as int? ?? 0; //Parameter that selects which tab to be displayed.
if (options == null)
{
options = new Options(tab);
options.Closed += (sender, args) =>
{
CloseOrNot();
};
//TODO: Open as dialog or not? Block other windows?
options.Show();
}
else
{
if (options.WindowState == WindowState.Minimized)
options.WindowState = WindowState.Normal;
options.SelectTab(tab);
options.Activate();
}
}
};
}
}
这样看有些麻烦,我们省略一些暂时对理解不重要的东西:
public ICommand OpenOptions
{
get
{
return new RelayCommand
{
CanExecutePredicate = a => true,
ExecuteAction = a =>
{
//这是个lambda表达式
}
};
}
}
实际上就是返回了一个new RelayCommand,这个RelayCommand是作者自定义的一个路由命令的类,代码如下:
/// <summary>
/// 路由命令
/// </summary>
internal class RelayCommand : ICommand
{
/// <summary>
/// 作者自定义的字段
/// </summary>
public Predicate<object> CanExecutePredicate { get; set; }
/// <summary>
/// 作者自定义的字段
/// </summary>
public Action<object> ExecuteAction { get; set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="canExecute"></param>
/// <param name="execute"></param>
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
CanExecutePredicate = canExecute;
ExecuteAction = execute;
}
/// <summary>
/// ICommand字段
/// </summary>
public RelayCommand()
{ }
/// <summary>
/// ICommand字段
/// </summary>
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
/// <summary>
/// ICommad字段
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
return CanExecutePredicate == null || CanExecutePredicate(parameter);
}
/// <summary>
/// ICommand字段
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
ExecuteAction(parameter);
}
}
使用路由的好处就是不管啥命令返回的都是RelayCommand类的实例,只要给该实例绑定上相应的方法就好了,方法可以随意写,上面作者就是为路由实例赋值了一个lambda表达式。
下面使用实例操作一下,下面的例子按下按钮之后修改button的context,为了方便我就直接使用上面ScreenToGif的RelayCommand。为了不与之前的代码冲突,我新加一个button:

新加的button的context同样是binding到Name属性,Command则是binding到了名为“ChangeName”命令上,该命令如下:

此时,MainViewModel.cs的所有代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfApp.ViewModel
{
class MainViewModel : INotifyPropertyChanged
{
#region INPC
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
#endregion
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
public ICommand ChangeName
{
get
{
return new RelayCommand() {
CanExecutePredicate = a => true,
ExecuteAction = a =>
{
Name = "ChangeName Command";
}
};
}
}
}
/// <summary>
/// 路由命令
/// </summary>
internal class RelayCommand : ICommand
{
public Predicate<object> CanExecutePredicate { get; set; }
public Action<object> ExecuteAction { get; set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="canExecute"></param>
/// <param name="execute"></param>
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
CanExecutePredicate = canExecute;
ExecuteAction = execute;
}
/// <summary>
/// ICommand字段
/// </summary>
public RelayCommand()
{ }
/// <summary>
/// ICommand字段
/// </summary>
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
/// <summary>
/// ICommad字段
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
return CanExecutePredicate == null || CanExecutePredicate(parameter);
}
/// <summary>
/// ICommand字段
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
ExecuteAction(parameter);
}
}
}
按照我的设定,按下第一个按钮会触发Button_Click方法(该方法在view的后台代码中,也就是我的工程中的MainWindow.xaml.cs文件)这是事件的方法,按下后会更改Name属性的内容,所有binding到该属性的控件内容都会跟随更改。
按下第二个按钮,则是触发ChangeName命令,该命令则是view的DataContext(也就是MainViewModel类)的ChangeName属性。按下后同样会修改Name属性的内容,所有所有binding到该属性的控件内容都会跟随更改。
下面debug一下:

喜大普奔,没有啥bug,哈哈哈哈哈哈
工程源代码上传在GitHub上了:https://github.com/feipeng8848/WPF-Demo
参考:https://www.codeproject.com/Articles/1052346/ICommand-Interface-in-WPF
WPF入门(3)——命令的更多相关文章
- WPF入门教程系列二十三——DataGrid示例(三)
DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...
- WPF入门教程系列二——Application介绍
一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只 ...
- WPF入门:数据绑定
上一篇我们将XAML大概做了个了解 ,这篇将继续学习WPF数据绑定的相关内容 数据源与控件的Binding Binding作为数据传送UI的通道,通过INotityPropertyChanged接口的 ...
- WPF入门教程系列三——Application介绍(续)
接上文WPF入门教程系列二——Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...
- 【转】【WPF】WPF 自定义快捷键命令(Command)
命令简介 WPF 中的命令是通过实现 ICommand 接口创建的.ICommand 公开两个方法(Execute 及 CanExecute)和一个事件(CanExecuteChanged).Exec ...
- WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...
- WPF入门教程系列(一) 创建你的第一个WPF项目
WPF入门教程系列(一) 创建你的第一个WPF项目 WPF基础知识 快速学习绝不是从零学起的,良好的基础是快速入手的关键,下面先为大家摞列以下自己总结的学习WPF的几点基础知识: 1) C#基础语法知 ...
- 16、WPF中的命令
一.前言 事件的作用是发布.传播一些信息,消息送达接收者,事件的使命就算完成了,至于如何响应事件送来的消息事件并不做规定,每个接收者可以使用自己的行为来响应事件,也就是说事件不具有约束力.命令能够在代 ...
- WPF中的命令简介
使用Prism委托命令Demo: WPF委托命令DelegateCommand的传参方式 在WPF中使用命令的步骤很简单 1.创建命令 2.绑定命令 3.设置命令源 4.设置命令目标 WPF中命令的核 ...
- WPF中的命令与命令绑定导航
1.WPF中的命令与命令绑定(一) (引入命令) 2.WPF中的命令与命令绑定(二)(详细介绍命令和命令绑定)
随机推荐
- Ubuntu 14.04 下安装redis后运行redis-cli 报出redis Connection refused错误【已解决】
在运行redis-cli运行后爆出错误,看了网上的都没有用例如:改ip,注释bind 127.0.0.1,或者是先运行./redis-server redis.conf,都没有用 只需要: 找到red ...
- 重读APUE(4)-fcntl和ioctl的区别
fcntl(File Control)-文件控制 ioctl(In/Out Control)-I/O控制 1. fcntl作用于文件,提供对文件的基础控制:ioctl作用于文件和设备对象,一般用来向设 ...
- 003-多线程-JUC线程池-几种特殊的ThreadPoolExecutor【newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool】
一.概述 在java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池: 以下方法是Executors下的静态方法,Ex ...
- java.util.concurrent.DelayQueue 源码学习
jdk1.8 DelayQueue,带有延迟元素的线程安全队列,当非阻塞从队列中获取元素时,返回最早达到延迟时间的元素,或空(没有元素达到延迟时间).DelayQueue的泛型参数需要实现Delaye ...
- 自己写了个简单的redis分布式锁【我】
自己写了个简单的redis分布式锁 [注意:此锁需要在每次使用前都创建对象,也就是要在线程内每次都创建对象后使用] package redis; import java.util.Collection ...
- [ML] Linear Discriminant Analysis
虽然名字里有discriminat这个字,但却是生成模型,有点意思. 判别式 pk 生成式 阅读:生成方法 vs 判别方法 + 生成模型 vs 判别模型 举例: 判别式模型举例:要确定一个羊是山羊还是 ...
- Redis的各项功能解决了哪些问题?(转)
http://www.cnblogs.com/linianhui/p/what-problem-does-redis-solve.html 先看一下Redis是一个什么东西.官方简介解释到:Redis ...
- Python中elasticsearch插入和更新数据的实现方法
Python中elasticsearch插入和更新数据的实现方法 这篇文章主要介绍了Python中elasticsearch插入和更新数据的实现方法,需要的朋友可以参考下 首先,我的索引结构是酱紫的. ...
- php 转化整型需要注意的地方
public function tt(){ $num = '19.90'; echo $num; echo '<br/>--------------<br/>'; echo 1 ...
- 处理HTTP请求
处理HTTP请求 当客户端浏览器通过URL访问web应用时,首先要做的就是获取用户提交的信息,也就是从HTTP请求数据中获得的信息.HTTP请求数据分为HTTP请求头和Body HTTP请求头包含了一 ...