当前位置: 首页 > news >正文

Avalonia 的命令基类和通知基类备份

备份一下,下次懒得写了,MVVM模式,顺带一个按钮激活的使用例子。有更好的建议欢迎提出。

1.CommandBase.cs


/// <summary>
/// 命令鸡肋(执行状态控制)
/// 空参 方法
/// </summary>
public class CommandBase : ICommand
{// 命令状态变更事件public event EventHandler CanExecuteChanged;// 存储命令执行逻辑(有参版本)private readonly Action<object> _executeWithParam;// 存储执行条件判断逻辑private readonly Func<object, bool> _canExecute;/// <summary>/// 构造函数:接收执行逻辑和执行条件/// </summary>public CommandBase(Action<object> execute, Func<object, bool> canExecute = null){_executeWithParam = execute ?? throw new ArgumentNullException(nameof(execute));_canExecute = canExecute;}/// <summary>/// 构造函数:接收无参执行逻辑和执行条件/// </summary>public CommandBase(Action execute, Func<object, bool> canExecute = null){_executeWithParam = _ => execute();_canExecute = canExecute;if (execute == null)throw new ArgumentNullException(nameof(execute));}/// <summary>/// 判断命令是否可执行/// </summary>public bool CanExecute(object parameter){// 如果有执行条件则使用条件判断,否则默认可执行return _canExecute == null ? true : _canExecute(parameter);}/// <summary>/// 执行命令逻辑/// </summary>public void Execute(object parameter){if (CanExecute(parameter)){_executeWithParam(parameter);}}/// <summary>/// 手动触发CanExecuteChanged事件,强制 UI 更新状态。/// </summary>public void RaiseCanExecuteChanged(){CanExecuteChanged?.Invoke(this, EventArgs.Empty);}
}

2.NotifyBase.cs


public class NotifyBase : INotifyPropertyChanged
{public event PropertyChangedEventHandler PropertyChanged;/// <summary>/// 属性改变通知方法/// </summary>/// <param name="propName"></param>public void NotifyChanged([CallerMemberName] string propName = ""){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));}
}

3.按钮激活示例

在ViewModel中

//数据表格的选中项SelectedItem数据源  
private ConfProduct _selectedConfProduct;public ConfProduct SelectedConfProduct{get => _selectedConfProduct;set{if (value == null){_selectedConfProduct = null;NotifyChanged();//激按钮状态控制UpdateBtnCommand.RaiseCanExecuteChanged();DeleteBtnCommand.RaiseCanExecuteChanged();//Dgv2数据初始化ResetDgv2ToInitialState();return;}_selectedConfProduct = value;NotifyChanged();UpdateBtnCommand.RaiseCanExecuteChanged();DeleteBtnCommand.RaiseCanExecuteChanged();ShowExistingProductDetails(); // Dgv2加载选中项}}#region 2. 命令声明public CommandBase UpdateBtnCommand { get; }public CommandBase DeleteBtnCommand { get; }#endregion#region 4. 构造函数(初始化命令,数据)public ProductSettingViewModel(){AddBtnCommmand = new CommandBase(DoAdd);UpdateBtnCommand = new CommandBase(DoUpdate, CanUpdateOrDelete);DeleteBtnCommand = new CommandBase(DoDelete, CanUpdateOrDelete);// 异步加载数据,避免UI阻塞_ = LoadDataAsync();}#endregion#region 按钮能否执行判断// 按钮是否可执行(选中产品才可用)private bool CanUpdateOrDelete(object parameter) => SelectedConfProduct != null;   //选中项不为空,返回true#endregion

激活和不激活的实例图片

未选中一行

选中一行

PS:添加我没有使用这套逻辑,默认一直处于能激活的状态。

4.解析

出自Ai的总结

结合CommandBase命令基类和SelectedConfProduct选中项属性,按钮激活 / 取消激活的逻辑形成了 **“条件绑定→状态判断→事件触发→UI 响应”** 的完整闭环,每个环节都有明确的代码支撑,具体拆解如下:

一、第一步:命令初始化 —— 绑定 “执行条件” 到命令

在 ViewModel 的构造函数中,UpdateBtnCommandDeleteBtnCommand初始化时,会将 “按钮可执行条件”(CanUpdateOrDelete)通过CommandBase的构造函数传入,完成 “条件与命令” 的绑定:

csharp

// ViewModel中命令初始化
UpdateBtnCommand = new CommandBase(DoUpdate, CanUpdateOrDelete);
DeleteBtnCommand = new CommandBase(DoDelete, CanUpdateOrDelete);
关键关联:CommandBase构造函数的作用

CommandBase的第二个构造函数(接收无参执行逻辑 + 执行条件)会将传入的CanUpdateOrDeleteFunc<object, bool>类型)赋值给私有字段_canExecute,为后续的 “可执行判断” 埋下依据:

csharp

// CommandBase构造函数(接收无参执行逻辑+执行条件)
public CommandBase(Action execute, Func<object, bool> canExecute = null)
{_executeWithParam = _ => execute(); // 包装无参执行逻辑(如DoUpdate、DoDelete)_canExecute = canExecute; // 保存执行条件(即ViewModel中的CanUpdateOrDelete)if (execute == null)throw new ArgumentNullException(nameof(execute));
}

二、第二步:可执行判断 ——CanExecute方法决定按钮状态

Avalonia 的按钮在绑定命令后,会自动调用命令的CanExecute方法判断自身是否激活(可点击),这个判断逻辑由CommandBaseCanExecute方法实现,且直接依赖第一步绑定的_canExecute(即CanUpdateOrDelete):

1. CommandBase.CanExecute的核心逻辑

csharp

public bool CanExecute(object parameter)
{// 如果有执行条件(_canExecute不为null),则执行条件判断;否则默认“可执行”return _canExecute == null ? true : _canExecute(parameter);
}
2. 最终的判断依据:CanUpdateOrDelete

ViewModel 中的CanUpdateOrDelete是实际的 “条件判断函数”,它直接关联SelectedConfProduct的状态 ——只有选中项不为 null 时,才返回 true(按钮激活)

csharp

private bool CanUpdateOrDelete(object parameter) => SelectedConfProduct != null;
场景举例
  • SelectedConfProduct = null(未选中 DGV1 行):CanUpdateOrDelete返回falseCommandBase.CanExecute返回false→按钮禁用(灰色,不可点击)。
  • SelectedConfProduct = 某产品实体(选中 DGV1 行):CanUpdateOrDelete返回trueCommandBase.CanExecute返回true→按钮激活(正常颜色,可点击)。

三、第三步:状态更新 ——SelectedConfProduct变化时触发事件

CanExecute方法只会在按钮初始化或 “命令状态变更事件” 触发时重新执行。因此,当SelectedConfProduct变化(选中 / 取消选中)时,必须通过CommandBase.RaiseCanExecuteChanged手动触发事件,强制 UI 重新检查CanExecute,更新按钮状态:

1. SelectedConfProduct变化时的触发逻辑

SelectedConfProductset访问器中,无论值是 “从 null 变为实体” 还是 “从实体变为 null”,都会调用RaiseCanExecuteChanged

csharp

public ConfProduct SelectedConfProduct
{get => _selectedConfProduct;set{if (value == null){_selectedConfProduct = null;NotifyChanged();// 关键:触发命令状态更新UpdateBtnCommand.RaiseCanExecuteChanged();DeleteBtnCommand.RaiseCanExecuteChanged();ResetDgv2ToInitialState();return;}_selectedConfProduct = value;NotifyChanged();// 关键:触发命令状态更新UpdateBtnCommand.RaiseCanExecuteChanged();DeleteBtnCommand.RaiseCanExecuteChanged();ShowExistingProductDetails();}
}
2. CommandBase.RaiseCanExecuteChanged的作用

该方法会主动触发CommandBaseCanExecuteChanged事件(ICommand接口的核心事件),而 Avalonia 的按钮会监听这个事件 —— 事件触发时,按钮会立即重新调用CanExecute方法,更新自身的激活状态:

csharp

public void RaiseCanExecuteChanged()
{CanExecuteChanged?.Invoke(this, EventArgs.Empty); // 触发状态变更事件
}

四、第四步:UI 响应 —— 按钮根据状态更新显示

Avalonia 的Button控件在绑定Command后,会自动完成以下逻辑,无需额外代码:

  1. 初始化时,调用Command.CanExecute(null)获取初始状态,设置按钮是否激活。
  2. Command.CanExecuteChanged事件触发时,再次调用Command.CanExecute(null),重新获取状态,并更新按钮的IsEnabled属性(激活 / 禁用)。

总结:完整逻辑链路(以 “删除按钮” 为例)

操作场景代码执行流程按钮状态结果
程序启动,未选中任何行1. SelectedConfProduct = nullCanUpdateOrDelete返回false;2. 按钮初始化调用DeleteBtnCommand.CanExecute(null)→返回false;3. 按钮禁用。禁用
用户点击 DGV1 某行1. SelectedConfProduct = 选中的产品实体;2. 调用DeleteBtnCommand.RaiseCanExecuteChanged()→触发CanExecuteChanged事件;3. 按钮监听事件,调用CanExecute(null)CanUpdateOrDelete返回true;4. 按钮激活。激活
用户点击 DGV1 空白区域1. SelectedConfProduct = null;2. 调用DeleteBtnCommand.RaiseCanExecuteChanged()→触发事件;3. 按钮调用CanExecute(null)→返回false;4. 按钮禁用。禁用

整个逻辑完全遵循 MVVM 模式:数据(SelectedConfProduct)的变化驱动命令状态,命令状态驱动 UI(按钮)的显示,无需在代码后置中直接操作按钮的IsEnabled属性,实现了 “数据与 UI 的解耦”。

http://www.dtcms.com/a/494698.html

相关文章:

  • 分布式和微服务的区别是什么?
  • windows10 安装 WSL2 及 ubuntu 24.04,Ubuntu中安装CUDA
  • 全链路智能运维中的多模态数据融合与语义对齐技术
  • 【DevOps】基于Nexus部署内网pypi代理镜像仓库操作手册
  • 微服务核心
  • 网站倒计时如何做自己的影视网站
  • 【DevOps】基于Nexus部署内网ubuntu 2204系统APT代理镜像仓库操作手册
  • 【开题答辩实录分享】以《开题报告 智能家居控制平台的构建》为例进行答辩实录分享
  • 建设论坛网站视频稿定设计官网入口
  • 利用R绘制箱线图
  • 【架构相关】tsconfig.json 与 tsconfig.node.json、tsconfig.app.json 的关系和作用
  • 烟台seo网站推广电商网站 手续
  • GLM-4.1V-Thinking vLLM部署调用
  • 从“生物进化”到算法优化:遗传算法的5个核心阶段
  • C++复习(1)
  • 云原生与分布式架构的完美融合:从理论到生产实践
  • 学习Python 03
  • Python中子类对父类方法的继承与改写
  • 深度学习之yolov3
  • 大型营销型网站建设网站做个seo要多少钱
  • 广州南建站时间dz网站建设教程
  • 【征文计划】Rokid 语音指令开发教程 【包含工程源码 和体验包APK】
  • 网站开发工程师需要什么证书网站风险解除
  • 回文串oj
  • Linux系统--信号(3--信号的保存、阻塞)
  • Linux内核架构浅谈44-Linux slab分配器:通用缓存与专用缓存的创建与使用
  • 无用知识研究:在trailing return type利用decltype,comma operator在对函数进行sfinae原创 [二]
  • APDU交互代码模拟
  • Linux性能分析系统和虚拟文件系统缓存初始化
  • 用python做网站和用php网站建设验收单意见怎么写