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

理解WPF Stylet中Command=“{s:Action 方法名}“的设计与实现 - 实践

前言

Stylet是我最近很喜欢使用的一个WPF框架,它的很多设计都体现了约定优于配置的思想。因此你会发现使用它非常方便,几乎不需要任何配置,开箱即用,只需知道它的一些约定即可。

查看Samples中Hello这个例子,只要在xaml中这样写:

Say Hello

然后你点击这个按钮,就会触发对应ViewModel中的SayHello方法,使用起来非常简单方便。这背后Stylet框架做了什么呢?让我们揭开它的神秘面纱吧!!

ActionExtension

先来看看ActionExtension,它位于Stylet.Xaml命名空间:

s:Action的第一阶段是XAML解析,这个阶段的核心任务是将XAML标记中的{s:Action SayHello}语法翻译成CommandAction实例。这个过程由ActionExtension标记扩展类完成,它是整个命令绑定系统的入口点。

当XAML解析器遇到{s:Action SayHello}时,会调用ActionExtension.ProvideValue方法:

HandleDependencyObject方法根据目标属性的类型进行分支处理:

对于命令绑定场景,CreateCommandAction方法创建CommandAction实例:

rootObject就是具有s:Action的页面:

View.ActionTarget

现在我们已经找到了View,但是想要触发的方法是在ViewModel上的,那么就要想办法找到对应的ViewModelStylet中是通过View.ActionTarget这个附加属性实现的。通过View.ActionTarget附加属性将ViewModel注入到可视化树中,使得后续阶段能够找到正确的命令执行目标。

先来看看View.ActionTarget的定义,位置在命名空间Stylet.Xaml下的View类中:

默认值:InitialActionTarget(一个特殊的标记对象)

继承性:FrameworkPropertyMetadataOptions.Inherits确保属性值可以沿着可视化树向下传递

View.Model属性被设置时,会触发PropertyChangedCallback,通过ViewManager建立视图和ViewModel的关联。

在将ViewViewModel关联起来的时候,设置了当前ViewActionTarget为对应的ViewModel

CommandAction

CreateCommandAction方法中会返回一个CommandAction

这里是在把当前这个Subject对象里的ActionTargetProperty的值‘拴’到 某个尚未显式的目标属性上,而且只让它从源(Subject)流向目标,不会反向同步。

这里的SubjectButton对象,为什么也能找到ActionTargetProperty这个属性呢?

由于ActionTargetProperty设置了FrameworkPropertyMetadataOptions.Inherits标志,这个属性会自动沿着可视化树向下传播:

Window (View.ActionTargetProperty)
├── UserControl (继承Window的View.ActionTargetProperty)
│ ├── Button (继承UserControl的View.ActionTargetProperty)
│ └── TextBox (继承UserControl的View.ActionTargetProperty)
└── Grid (继承Window的View.ActionTargetProperty)

但是现在还没完成绑定,只是绑定的一端,还需要设置将这个属性绑定到哪里。

BindingOperations.SetBinding(this, targetProperty, multiBinding);ActionBasetargetProperty依赖属性绑定到View.ActionTargetProperty

你会发现现在并没有绑定到ViewModel,只是View.ActionTargetProperty的默认值:

由于targetProperty依赖属性从nullView.InitialActionTarget也会触发UpdateActionTarget,不过这一次不做任何处理,直接返回:

当设置View.ActionTargetProperty的值为对应的ViewModel时:

就又会触发UpdateActionTarget方法,这一次拿到了对应的ViewModel

拿到ViewModel上的方法:

拿到是否可以执行对应命令的属性:

现在重点来关注一下这里:

Expressions.ConstantExpression targetExpression = Expressions.Expression.Constant(newTarget);
Expressions.MemberExpression propertyAccess = Expressions.Expression.Property(targetExpression, guardPropertyInfo);
this.guardPropertyGetter = Expressions.Expression.Lambda<Func<
bool>
>(propertyAccess).Compile();

这段代码在运行时动态编译一段表达式树,生成一个无参、返回 bool的委托(Func<bool>),用来快速读取某个对象的布尔型属性值。

第一行相当于就是使用这个newTarget对象,第二行就是访问这个newTarget对象的CanSayHello属性,相当于newTarget.CanSayHello

Expression.Lambda<Func<bool>>将表达式树包装成一个无参Lambda表达式(形如 () => newTarget.CanSayHello)。

.Compile()把表达式树编译成可执行IL ,生成一个静态缓存的委托Func<bool>

然后调用this.UpdateCanExecute();触发CanExecuteChanged事件,就会执行CanExecute方法,在这个方法中就使用到了刚刚生成的获取newTarget.CanSayHello属性的委托:

现在是false,命令无法执行:

当我输入小明的时候就修改了这个属性值,就会触发CanExecuteChanged事件:

就又会调用刚刚生成的那个获取newTarget.CanSayHello属性的委托:

这一次返回true,命令可以执行。

当我点击按钮的时候,如果命令可以执行,就会执行Execute方法

这样就会执行ViewModel中对应的方法。

以上就是个人对于WPF Stylet中Command="{s:Action SayHello}"的设计与实现的理解。

http://www.gsyq.cn/news/19114.html

相关文章:

  • laya自定义滚动条
  • SigOJ提交语言帮助文档 - lkjy
  • 优维科技一面
  • 深入解析:FreeRTOS内存分配与STM32内存布局详解
  • 2025婚纱照拍摄推荐,南通造物摄影有限公司专业团队打造梦幻
  • 2025精密弹簧优质厂家推荐:蓝侨盈科技,精准弹性解决方案!
  • 有限空间作业安全无死角!AI 视觉守护人员与操作合规
  • 2025抖音推广服务商最新推荐榜:精准引流与高效转化的营销利
  • 4K Wallpaper mac v2.7.dmg 安装教程(Mac电脑详细安装步骤4K壁纸Mac下载安装)
  • 2025甘肃西服定制店推荐榜单:匠心工艺与贴心服务的完美结合
  • 2025表面瑕疵检测设备厂家最新推荐:精准高效,工业品质之选
  • 2025环氧板定制厂家推荐:一博科技材料,专业定制品质卓越!
  • CSP-S模拟29 2025.10.11
  • 最简单实用的SQL注入检测方法:Break Repair技巧详解
  • 2025螺杆泵厂家最新推荐榜:高效稳定与优质服务的行业首选!
  • 2025南通婚纱摄影最新推荐榜:创意拍摄与贴心服务的完美结合
  • 实用指南:微波雷达模块在智能家居中的具体应用案例有哪些?
  • 尝试茶叶数据集
  • 20251011
  • (第四次)回归与决策树
  • 2025机械加工实力厂家推荐:鑫铭机械专业制造,品质卓越首选
  • 高考语文做法
  • 2025石头纸设备批发厂家推荐鼎浩包装,环保高效生产首选!
  • 2025液压阀块供货厂家最新推荐榜:品质卓越与高效服务的行业
  • centos安装atop工具,检测服务器情况
  • 2025深圳网站建设公司最新推荐榜:创意设计与专业服务引领者
  • 2025智能照明系统直销厂家推荐:八渡科技,智慧生活首选!
  • 最小乘积模型与快速凸包构造学习笔记
  • 2025网络营销推广TOP5榜单:精准引流与高效转化的营销专
  • 基于 Scala 的英文数字验证码识别系统设计与实现