使用Fody PropertyChanged时属性变更未触发CanExecute的问题
问题原因与解决方案
核心问题
你的ViewModel没有监听MyModel内部属性的变更事件,同时Model的分部类配置存在冗余,导致Fody的属性变更通知逻辑未正确生效,最终命令的CanExecute状态无法自动更新。
1. Model分部类的冗余配置干扰Fody注入
你手动声明了PropertyChanged事件,但[AddINotifyPropertyChangedInterface]特性会自动为类实现INotifyPropertyChanged接口(包括事件定义和属性变更通知逻辑),手动添加事件会破坏Fody的自动注入流程。
修复代码:
namespace FodyPropertyChange { [AddINotifyPropertyChangedInterface] public partial class Model { // 移除手动声明的PropertyChanged事件,仅保留特性即可 } }
2. ViewModel未感知Model内部属性变化
当前ViewModel仅在MyModel实例被替换时(即MyModel属性的setter)调用TestCommand.RaiseCanExecuteChanged(),但MyModel内部的Name/Age属性变化时,ViewModel无法感知,因此不会更新命令的可执行状态。
修复代码:
public class MainWindowViewModel : BindableBase { public DelegateCommand TestCommand { get; set; } public MainWindowViewModel() { TestCommand = new DelegateCommand(OnTestCommand, CanExecute); // 订阅MyModel的属性变更事件 MyModel.PropertyChanged += MyModel_PropertyChanged; } private void MyModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { // Model内部属性变化时,更新命令可执行状态 TestCommand.RaiseCanExecuteChanged(); } private bool CanExecute() { return MyModel.Age > 0 && !string.IsNullOrEmpty(MyModel.Name); } private void OnTestCommand() { MessageBox.Show("Hi"); } private Model _MyModel = new Model(); public Model MyModel { get { return _MyModel; } set { // 先取消旧实例的事件订阅,避免内存泄漏 if (_MyModel != null) _MyModel.PropertyChanged -= MyModel_PropertyChanged; SetProperty(ref _MyModel, value); // 订阅新实例的事件 if (_MyModel != null) _MyModel.PropertyChanged += MyModel_PropertyChanged; TestCommand.RaiseCanExecuteChanged(); } } }
注:ViewModel继承的
BindableBase已实现INotifyPropertyChanged,无需手动重复声明接口和事件。
3. 额外验证点
- 确认已通过NuGet安装
PropertyChanged.Fody包; - 检查
FodyWeavers.xml的“复制到输出目录”设置为“始终复制”,确保编译时Fody能读取配置。
修复完成后,当文本框修改MyModel的属性时,Model会触发PropertyChanged事件,ViewModel收到事件后更新命令的可执行状态,按钮会根据CanExecute的返回值自动启用/禁用。
内容的提问来源于stack exchange,提问作者Khosro
相关产品推荐
相关产品推荐

