WPF 架构困惑 RE : Routed Commands, 事件和手势

标签 wpf xaml routed-commands

在学习 WPF 的过程中,我阅读了大量的书籍和网站。我似乎一直回避的一件事是我们应该如何正确连接 RoutedCommands。在一篇文章中,作者指出 XAML 文件的代码隐藏应该只包含对 InitializeComponent 的调用。我可以支持这一点。它使 XAML 文件只不过是一个演示文稿文档,并满足了我对关注点分离的邪恶渴望。

另一方面,我见过的每个解决双击事件的示例似乎都希望您编写代码。据我了解,我们希望摆脱代码隐藏文件中的重复代码(并且,我再次支持这一点),所以在我看来,这不是正确的方法。菜单命令、工具栏按钮单击等也是如此。

例如,想象一下我有一个打开文档的命令。该命令必须显示“打开”对话框,然后打开文档并将其缓存在应用程序状态中。 (此应用程序仅允许您一次处理一个文档。)用户可以通过以下任一方式调用此命令:

  • 从菜单中选择"file"->“打开”。
  • 输入 Ctrl+O。
  • 单击工具栏上的“打开”按钮。

如果我信任 Web 上的大多数源,我必须编写至少两个 Click 事件处理程序,然后调用该命令,从而污染代码隐藏文件。在我看来,这似乎违背了拥有命令的目的。我认为在某处读到,有一种方法可以在 XAML 中以声明方式将命令绑定(bind)到这些东西,它会为您执行此操作,甚至在命令无法执行时禁用该命令。但现在我似乎找不到它,也找不到如何做到这一点的好例子。

有人可以向我解释一下吗?此时一切都开始看起来像巫术和弹片。

最佳答案

避免命令代码隐藏的常用方法是避免使用 RoutedCommands。在 MVVM(模型- View - View 模型)主题的各种变体中,人们倾向于使用 ICommand 的自定义实现。他们编写了一个放置在 UI 的 DataContext 中的 ViewModel 类。该ViewModel公开了ICommand类型的属性,并且这些命令属性通过数据绑定(bind)连接到菜单项、按钮等。 (它通常只是反复使用的 ICommand 的一个实现 - 在网络上搜索 RelayCommand 或 DelegateCommand 或 DelegatingCommand,你会看到这种模式 - 它基本上是 ICommand 作为委托(delegate)的包装器,并且可选支持启用/禁用。)

在这个习惯用法中,您几乎从不使用像 ApplicationCommands.Open 这样的内置命令。这些东西的唯一真正用途是如果您希望焦点敏感命令由控件本质上处理。例如,文本框内置了用于编辑、复制、粘贴等的命令处理。这避免了代码隐藏问题,因为它是一个完整的自定义控件,而自定义控件实际上并不具有代码隐藏本身 - 它们都是代码。 (Xaml 实际上位于一个完全独立的对象(模板)中,并且实际上并不是控件的一部分。)并且在任何情况下,它都不是您的代码 - 您拥有一个已经知道如何支持命令的控件,因此您可以完全保留在此处的 Xaml 中。

命令路由在该特定场景中很有趣,因为它允许您放置一组与各种编辑控件关联的菜单项,并且路由系统会根据焦点所在位置确定哪个文本框(或其他内容)将处理命令。如果这不是您想要的,那么命令路由可能对您没有多大用处。

但是,这里有一个更大的问题:当您发现确实必须将代码放在代码隐藏中时该怎么办。如果您使用自定义 ICommand 实现,命令通常不是该场景的示例(尽管有奇怪的异常(exception)),但稍微更有趣的用户输入事件是。您提到了双击,而且,如果您正在进行任何类型的不寻常的交互,您往往需要诸如鼠标向上/向下之类的操作。

在这种情况下,通常的方法是硬着头皮将代码放在代码隐藏中,但您尝试将每个事件处理程序保持为一行。基本上,您的代码隐藏只是调用 View 模型上的相关方法,这才是真正处理事件的方法。

它的可爱之处在于它使编写自动化测试变得非常容易。想要模拟鼠标进入 UI 的特定部分吗?无需搞乱单元测试 UI 自动化框架 - 只需直接调用相关方法即可!

关于WPF 架构困惑 RE : Routed Commands, 事件和手势,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4101729/

相关文章:

WPF 覆盖 ContextMenu 样式 - DropShadowEffect 不起作用

wpf - 如何使用 MVVM 在 WPF 中绑定(bind)图钉位置?

c# - WPF Grid.IsSharedSizeScope 跨多个网格

c# - 查找 RoutedEvent 的目的地

wpf - 自定义附加命令

c# - 如何在 DLL 中捆绑 index.html、jquery.js、main.css 以在 WPF 中使用?

c# - WPF TabControl with Materials Design(没有 Dragablz)

xaml - Xamarin.Forms 中如何添加图像和图标?

c# - PreviewExecuted 后未调用 Executed

c# - WPF如何在两个页面之间传递值