使用CommunityToolkit.Mvvm时RelayCommand通知CanExecuteChanged引发栈溢出异常
问题根源分析
你遇到的System.StackOverflowException是无限递归调用导致的:
当NotifyCanExecuteChanged()被调用时,WPF会重新评估命令的CanExecute状态,也就是再次调用CanNavigate()方法;而你在CanNavigate()里又调用了NotifyCanExecuteChanged(),这就形成了无限循环,最终栈被撑爆抛出异常。
解决步骤
1. 移除CanExecute方法内的错误调用
首先删掉CanNavigate()里的this.PreviousViewCommand.NotifyCanExecuteChanged();,CanExecute方法只负责做状态判断,绝对不能在这里触发状态更新操作。
修改后的CanNavigate方法:
private bool CanNavigate() { return _navigationServices.CanNavigate; }
2. 在导航状态变更时主动触发更新
要让按钮状态随导航服务变化自动更新,需要在导航服务的CanNavigate属性改变时,主动通知命令刷新状态:
- 给导航服务添加状态变更事件
- 在ViewModel中订阅该事件,事件触发时调用命令的
NotifyCanExecuteChanged()
示例:修改导航服务类
public class NavigationServices { private bool _canNavigate; public bool CanNavigate { get => _canNavigate; private set { if (_canNavigate != value) { _canNavigate = value; // 状态变更时触发事件 CanNavigateChanged?.Invoke(this, EventArgs.Empty); } } } // 定义状态变更事件 public event EventHandler CanNavigateChanged; public object GetPreviousView() { // 执行你的导航逻辑... // 根据导航栈实际情况更新CanNavigate状态 CanNavigate = // 比如:导航栈长度 > 1 ? true : false; return // 返回对应视图模型; } }
示例:在ViewModel中订阅事件
public MainViewModel() { _navigationServices = new NavigationServices(); PreviousViewCommand = new RelayCommand(PreviousViewModel, CanNavigate); // 订阅导航服务的状态变更事件,触发命令更新 _navigationServices.CanNavigateChanged += (sender, e) => PreviousViewCommand.NotifyCanExecuteChanged(); } private void PreviousViewModel() { this.CurrentPageViewModel = _navigationServices.GetPreviousView(); }
核心原则
RelayCommand的CanExecute方法仅用于判断当前是否可执行,状态更新的触发逻辑应该放在数据源(导航服务)的状态变更点,而不是判断方法内部,这样才能避免递归循环问题。
内容的提问来源于stack exchange,提问作者benporter
相关产品推荐
相关产品推荐

