我正在使用 MVVM 设计模式构建应用程序,并且我想使用 ApplicationCommands 类中定义的 RoutedUICommands。由于 View 的 CommandBindings 属性(读取 UserControl)不是 DependencyProperty,我们无法将 ViewModel 中定义的 CommandBindings 直接绑定到 View。我通过定义一个抽象的 View 类来解决这个问题,该类以编程方式绑定它,基于 ViewModel 接口,该接口确保每个 ViewModel 都有一个 CommandBindings 的 ObservableCollection。这一切都很好,但是,在某些情况下,我想执行在不同类(视图和视图模型)相同命令中定义的逻辑。例如,保存文档时。
在 ViewModel 中,代码将文档保存到磁盘:
private void InitializeCommands()
{
CommandBindings = new CommandBindingCollection();
ExecutedRoutedEventHandler executeSave = (sender, e) =>
{
document.Save(path);
IsModified = false;
};
CanExecuteRoutedEventHandler canSave = (sender, e) =>
{
e.CanExecute = IsModified;
};
CommandBinding save = new CommandBinding(ApplicationCommands.Save, executeSave, canSave);
CommandBindings.Add(save);
}
乍一看,前面的代码就是我想要做的,但是文档绑定到的 View 中的 TextBox 只有在失去焦点时才更新它的 Source。但是,我可以通过按 Ctrl+S 来保存文档而不会失去焦点。这意味着文档在源中更新的更改之前保存,有效地忽略了更改。但是由于出于性能原因将 UpdateSourceTrigger 更改为 PropertyChanged 不是一个可行的选项,因此必须在保存之前强制进行更新。所以我想,让我们使用 PreviewExecuted 事件在 PreviewExecuted 事件中强制更新,如下所示:
//Find the Save command and extend behavior if it is present
foreach (CommandBinding cb in CommandBindings)
{
if (cb.Command.Equals(ApplicationCommands.Save))
{
cb.PreviewExecuted += (sender, e) =>
{
if (IsModified)
{
BindingExpression be = rtb.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
}
e.Handled = false;
};
}
}
但是,将处理程序分配给 PreviewExecuted 事件似乎完全取消了该事件,即使我明确地将 Handled 属性设置为 false。所以我在前面的代码示例中定义的 executeSave 事件处理程序不再执行。请注意,当我将 cb.PreviewExecuted 更改为 cb.Executed 时,两段代码都会执行,但顺序不正确。
我认为这是 .Net 中的一个错误,因为您应该能够向 PreviewExecuted 和 Executed 添加一个处理程序,并让它们按顺序执行,前提是您没有将事件标记为已处理。
任何人都可以确认这种行为吗?还是我错了?这个错误有解决方法吗?