更新到 Catel 4.4.0 后未触发命令的 CanExecute 方法

CanExecute method of command not firing after update to Catel 4.4.0

我最近将我的应用程序从 Catel 3.9.0 更新到 4.4.0。除了出现在我大多数视图中的打印按钮外,一切正常。

该应用程序允许客户 select 并加载一个文本文件,然后对其进行解析和验证。如果有任何错误,它们将显示在网格控件的视图中。显示任何错误还应启用“打印”按钮,让客户预览和打印错误报告。

视图架构是:

MyView.xaml (Catel UserControl)
    CommonErrorsWarnings.xaml (Catel UserControl)
        ErrorsAndWarningsGrid (DevExpress GridControl)

ErrorsAndWarningsGrid 绑定到关联 ViewModel 的公共父 class 中的 ObservableCollection。此 ObservableCollection 包含包含验证 errors/warnings.

的对象

View 上还有一个打印按钮,绑定到公共父 ViewModel class 上的命令。它具有以下 "can execute" 方法:

/// <summary>
/// Method to check whether the PrintReport command can be executed.
/// </summary>
/// <returns><c>true</c> if the command can be executed; otherwise <c>false</c></returns>
protected virtual bool OnPrintReportCanExecute()
{
    Debug.Print(string.Format("OnPrintReportCanExecute called in [{0}].  Errors/Warnings count = {1}", this.Title, this.RecordErrorsAndWarnings.Count));
    return this.RecordErrorsAndWarnings != null && this.RecordErrorsAndWarnings.Count > 0;
}

(Debug.Print 语句只是为了帮助了解何时调用此方法。)

所有这一切在 Catel 3.9.0 中运行良好——当客户加载文本文件并将验证错误添加到 RecordErrorsAndWarnings 集合时,打印按钮被启用。移动到 4.4.0 后,它已停止工作。 OnPrintReportCanExecute 方法不像在 3.9.0 中那样经常被调用,而且在 RecordErrorsAndWarnings 计数大于 0 时也不会被调用。看起来 CanExecute 方法没有被调用 during/after 集合已更新。它似乎只在创建 ViewModel 时集合是第一个 "set" 时被调用,但当集合是 "gotten" 时不会调用它来向它添加项目。

我尝试了 Catel documentation 中的一些建议:手动添加有趣的属性并注册 ViewPropertySelector,但似乎都不起作用。

临时解决方法(来自另一个 SO question)是在更新集合后调用 ViewModelCommandManager.InvalidateCommands(true),但我担心是否有 better/simpler 解决方案。

如果您有任何疑问或需要更多信息,请告诉我。谢谢!

出于性能原因,Catel 不再自动订阅 CommandManager 以使状态无效(节省 lot 的 CanExecute 调用)。如果您想要恢复所有这些行为,您可以创建一个自定义 class 订阅命令管理器并为您使命令无效。

2 条免责声明

  1. 这是出于某种原因(性能)而被删除的,因此这不是推荐的方法。但这可以让你找回旧的行为。
  2. 我还没有测试过这段代码,但它应该几乎开箱即用。

代码

public class RequeryAllTheThings
{
    private IViewModelManager _viewModelManager;

    public RequeryAllTheThings(IViewModelManager viewModelManager)
    {
        Argument.IsNotNull(() => viewModelManager);

        _viewModelManager = viewModelManager;

        System.Windows.Input.CommandManager.RequerySuggested += OnCommandManagerRequerySuggested;
    }

    private void OnCommandManagerRequerySuggested(object sender, SomeEventArgs e)
    {
        InvalidateCommands();
    }

    private void InvalidateCommands()
    {
        var viewModels = _viewModelManager.ActiveViewModels;
        foreach (var viewModel in viewModels)
        {
            var viewModelBase = viewModel as ViewModelBase;
            if (viewModelBase != null)
            {
                var viewModelCommandManager = viewModelBase.GetViewModelCommandManager();
                viewModelCommandManager.InvalidateCommands();
            }
        }
    }
}