C# Catel 4.4.0更新后不触发命令的CanExecute方法

C# Catel 4.4.0更新后不触发命令的CanExecute方法,c#,wpf,mvvm,catel,C#,Wpf,Mvvm,Catel,我最近将我的应用程序从Catel 3.9.0更新为4.4.0。除了在我的大多数视图中出现的“打印”按钮外,一切都很正常 该应用程序允许客户选择并加载文本文件,然后对其进行解析和验证。如果有任何错误,它们将显示在栅格控件的视图中。显示任何错误还应启用打印按钮,以便客户预览并打印错误报告 视图体系结构是: MyView.xaml (Catel UserControl) CommonErrorsWarnings.xaml (Catel UserControl) ErrorsAn

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

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

视图体系结构是:

MyView.xaml (Catel UserControl)
    CommonErrorsWarnings.xaml (Catel UserControl)
        ErrorsAndWarningsGrid (DevExpress GridControl)
ErrorsAndWarningGrid绑定到关联ViewModel的公共父类中的ObservableCollection。此ObservableCollection保存包含验证错误/警告的对象

视图上还有一个打印按钮,该按钮绑定到公共父ViewModel类上的命令。它具有以下可执行方法:

/// <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;
}
Print语句只是为了帮助了解何时调用此方法

所有这些在Catel 3.9.0中都运行良好-当客户加载文本文件并将验证错误添加到RecordErrors和Warnings集合时,打印按钮被启用。移动到4.4.0后,它已停止工作。OnPrintReportCanExecute方法不像3.9.0中那样频繁调用,并且在RecordErrorsAndWarnings计数大于0时从不调用。在集合更新期间/之后,似乎没有调用CanExecute方法。它似乎只有在创建ViewModel时首次设置集合时才被调用,但在集合向其中添加项目时才被调用

我尝试过Catel中的一些建议:手动添加有趣的属性和注册ViewPropertySelector,但这两种方法似乎都不起作用

另一个SO的临时解决方法是在更新集合后调用ViewModelCommandManager.InvalidateCommandstrue,但我关心的是是否有更好/更简单的解决方案


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

出于性能原因,Catel不再自动订阅CommandManager以使状态无效,从而节省了大量CanExecute调用。如果希望恢复所有这些行为,可以创建一个自定义类,订阅命令管理器并使命令无效

2免责声明

删除此选项是出于性能原因,因此这不是推荐的方法。但这可以让你恢复以前的行为。 我还没有测试过这段代码,但它应该可以很好地运行。 代码


谢谢你的回复!我使用了你的类,并在我的App-OnStartup方法中实例化了它,它似乎工作得很好。我没有注意到演出的热播。我的应用程序就像一个批处理程序:客户加载记录的文本文件,应用程序处理并验证它们,然后应用程序显示结果。客户没有太多的互动要做。我计时运行1000到50000条记录,50K条记录只增加了7秒,总共2分3秒,所以我不太担心。再次感谢!我确实注意到了一些有趣的事情:我有另一个应用程序没有显示这个可以执行的问题。它们的操作方式类似,但在第二个应用程序中,ViewModel直接从ViewModelBase下降。在我的第一个应用程序中,ViewModel从一个中间VM派生,然后从ViewModelBase派生。这能解释这个问题吗?只是想知道。谢谢。这是因为Catel会在属性更改时自动重新计算命令。但是,如果vm属性没有更改,则没有理由自动重新计算命令。这就是为什么您的第一个应用程序需要此附加代码。谢谢!我想我明白了。如果我有一些空闲时间,我可能会做一个小例子,这样我就能更好地理解这一点。
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();
            }
        }
    }
}