【问题标题】:Is it an antipattern to use both traditional click events and ICommand?同时使用传统的点击事件和 ICommand 是一种反模式吗?
【发布时间】:2015-10-14 07:49:40
【问题描述】:

一般来说,我认为使用 ICommands 来处理需要执行某些操作(例如保存用户输入)的按钮单击是一种很好的做法。然而,当按钮在 UI 上做一些严格的事情时,比如打开一个模态对话框,视图模型不需要处理它,甚至不需要知道它发生了。在这种情况下,似乎只使用按钮的 Click 事件处理程序更有意义,但这样的混合和匹配似乎是一种潜在的反模式。我这样想对吗?

例如:

var openModalButton = new Button();
openModalButton.Click += OnModalButtonClick;

//Elsewhere in the view...
var saveInputButton = new Button { Command = _vm.SaveInput };

通过查看代码并不清楚为什么要使用命令,以及为什么要使用点击事件。

【问题讨论】:

  • 我强烈推荐阅读this answer。它坚持使用ICommand 来绑定视图。但是纯粹的 UI 逻辑仍然在代码隐藏中定义。我喜欢这种类型的接口解决方案的地方在于它强制各种 WPF 项目与它处理这些类型的应用程序操作的方式保持一致(当然,假设你有你的 Windows 实现它)。

标签: c# wpf mvvm


【解决方案1】:

杰迪迪亚,

我通常会像你一样混搭。通常(对我而言)只有 1 或 2 种这样的情况,而模式和架构的想法是让代码更易于阅读和简化事情。添加大量代码只是为了确保遵循 MVVM 模式,在这种情况下似乎会使事情复杂化。也就是说,我看到的通常处理方式是使用 ICommand 将按钮绑定到您的 ViewModel,然后使用“中介”或“服务”来启动对话框。您可以在 Google 搜索:“如何以 mvvm 方式处理打开模式对话框”和/或查看:

Open dialog in WPF MVVM

The "pretty" way to make a modal dialog in WPF with Prism and MVVM Pattern

Handling Dialogs in WPF with MVVM

祝你好运!

戴夫

【讨论】:

    【解决方案2】:

    当然,正如 Robin 指出的那样,一致性很重要。但是,在某些情况下,您不希望 ViewModel 参与其中。然后别无选择,我认为最好在这里打破一致性,但不要通过处理 ViewModel 中不属于它的工作的东西来打破模式 (MVVM)。

    您以模态对话框为例,我不同意 ViewModel 不应该知道它。当然 ViewModel 不允许直接打开那个对话框,设置它的所有者等等。但对话框很可能是工作流的一部分,了解 ViewModel 中工作流的当前状态就很好了。所以中间应该有一层。允许您说“我想显示 X 的 UI”并通过使用模式对话框解决此问题的服务或类似的东西。 ViewModel 不知道模态对话框,但它知道当前状态,例如它正在询问用户是否保存更改。当然,这需要某种基础设施来处理特殊情况和棘手的部分。 MVVM 框架为此提供了解决方案。

    如果这听起来对您的应用程序来说太过分了,只需将事件处理放在视图后面的代码中即可。不是很漂亮的风格,但它并没有打破 MVVM 模式。

    一句话:混合比违反模式更好。

    【讨论】:

    • 在编写上述 Robin 时提到了依赖注入。这正是使我们能够将模式对话框和 ViewModel 结合在一起的原因。您可以选择自己实现 DI,例如通过使用接口和服务,或者您可以使用现有框架之一。无论如何,您必须选择是否值得付出努力。如果应用程序非常小,它可能不会,但如果它是一个巨大的应用程序,您最好花一些时间来找到处理此问题的技术和框架的组合。
    【解决方案3】:

    我认为这是一种反模式,或者至少不是很酷的事情,首先因为你混合了这两种方法并且不一致,其次因为我认为这需要始终在 Command 而不是事件处理程序,为什么?

    视图模型不需要处理它,甚至不需要意识到它 发生了。在这种情况下,似乎只使用更有意义 按钮的 Click 事件处理程序

    并非如此,除了命令可以帮助您将对象与执行命令的逻辑分开,从而使其松散耦合之外,它还有助于增强代码的可重用性,例如将来有人可能想要将该按钮更改为可能具有不同事件的全新控件,以及相应事件的不同参数... 这会破坏您的代码,但是使用命令更好,并且始终兼容和可重用。

    此外,Laurent Bunion 在this article 中解释了事件的问题所在:

    尽管事件处理程序具有所有实用性,但也有一个问题的一面 效果:它们可以在实例之间创建紧密耦合 公开事件和订阅它的实例。系统 需要跟踪事件处理程序以便它们可以被执行 引发事件时,但由此产生的强链接可能 防止垃圾收集。当然,如果 事件处理程序是一种静态方法,但并不总是可以 仅使用静态方法处理所有事件。这是一个常见的原因 用于 .NET 中的内存泄漏。

    事件和它的紧密耦合的另一个结果 handler 是在 XAML 中声明的 UI 元素的事件处理程序 必须在附加的代码隐藏文件中找到。如果它不存在(或 如果没有附加的代码隐藏文件),编译将失败 有错误。使用列表时,这尤其是一个问题 控件和相关的数据模板。当模板的一个元素 必须启动,可以定义事件处理程序,但作为 结果,DataTemplate 不能移动到外部 资源字典。

    【讨论】:

      猜你喜欢
      • 2017-07-22
      • 2021-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多