2021-05-06

WPF之自定义委托命令

WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类,还可以使用自定义命令。自定义命令直接在命令目标上起作用,而不像RoutedCommand那样先在命令目标上激发出路由事件等外围控件捕捉到事件后再"翻过头来"对命令目标加以处理。

常用命令

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)  {   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)  {   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









原文转载:http://www.shaoqun.com/a/725756.html

跨境电商:https://www.ikjzd.com/

薇美铺:https://www.ikjzd.com/w/2312

bap:https://www.ikjzd.com/w/1492


WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类,还可以使用自定义命令。自定义命令直接在命令目标上起作用,而不像RoutedCommand那样先在命令目标上激发出路由事件等外围控件捕捉到事件后再"翻过头来"对命令目标加以处理。常用命令WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类,还可以使用自定义
网易考拉海购大促:https://www.ikjzd.com/w/1052
camel:https://www.ikjzd.com/w/331.html
淘粉吧:https://www.ikjzd.com/w/1725
流量碎片化背景下,我国跨境电商如何变革?:https://www.ikjzd.com/home/100948
速看!你售卖的产品与你的营业执照经营范围一致吗?:https://www.ikjzd.com/home/121531
面对亚马逊二审,这样做通过机率更高!:https://www.ikjzd.com/home/118037

No comments:

Post a Comment