【问题标题】:MVVM ICommand alternativeMVVM ICommand 替代方案
【发布时间】:2009-05-29 15:31:16
【问题描述】:

我已经开始创建一个 wpf mvvm 应用程序。 ViewModel 的一个重要组成部分似乎是一堆 ICommand,它们具有允许视图与 viewmodel 交互的松散耦合方式。

我的问题是,为什么我不能直接绑定到一个方法?

我使用了 Josh Smith 的 ICommand 的 RelayCommand 实现,它允许您将 delgate 注入到 ICommand 对象中,但实际上,有没有更简单的方法可以让按钮按下来调用视图模型中的方法?

我是 MVVM 新手,我相信我需要一些启发

【问题讨论】:

  • 您可以绑定到一个方法:... 但是您可能希望将启用/禁用逻辑和执行逻辑合并在一起?这就是你需要指挥的原因。

标签: wpf mvvm viewmodel


【解决方案1】:

您不能直接绑定到方法,因为Button(例如)没有接受委托的属性。相反,它有一个Command 类型的ICommand 属性。 RelayCommand(又名DelegateCommand)只是一个包裹代表的ICommand

我看不出为什么视图无法通过标记扩展绑定到视图模型上的特定方法的技术原因:

<Button Command="{ViewModelMethod SomeMethodName}"/>

但是,这会更慢,并且会增加视图和视图模型之间的耦合。如果视图只知道 ICommand 类型的视图模型上的属性,则该命令的实现可能会完全改变(或方法可能被重命名),而视图不知道。

【讨论】:

  • 为什么会慢?是否需要使用反射?但我确实理解你提到的耦合问题。
  • 好吧,实际上我不认为它会慢很多,因为绑定到 viewmodel 命令也使用反射。然而,这种方法有一个缺点:由于 ViewModelCommand 标记扩展不是绑定,因此当 ViewModel 更改时它不会被更新:它只会被评估一次(除非它挂钩到 DataContextChanged 事件以重新评估,但那是另一回事了。 ..)
  • 首先,我说的是“慢”,而不是“慢”。重要的区别在于。其次,我说的是要调用的方法的解析和调用,而不是绑定本身。使用由 VM 创建的委托将比从视图中反射解析方法更快。因此,除了所有其他缺点之外,从视图中执行此操作会更慢。
【解决方案2】:

我完全不同意。

调用速度无关紧要:命令是用户交互,它们从不需要速度。

关于耦合的论点也是有缺陷的。为什么 {Binding MyProperty} 没有耦合,而 {ViewMethod MyMethod} 是?

要求将特制的“命令”包裹在方法周围是一种愚蠢的做法。命令可能是隐蔽的有用实现,但我们已经在 C# 中有方法,用大而笨重的东西替换它们是不对的。

还有关于 MarkupExtension 和 Binding 的事情,真的很难。但这是可以完成的。其实已经搞定了,你可以看看 CodePlex 上的 MethodCall 项目: http://methodcallthing.codeplex.com/

您可以使用绑定来为方法选择“this”,并且可以使用绑定来获取参数。所有这些都是实时的,即在调用命令时计算。另一个好处是方法调用的推送结果,您也可以为此使用绑定(OneWayToSource)。

【讨论】:

  • +1 用于纠正 Kent Boogaart 答案中的缺陷。您的解决方案很有趣,但它不承认 ICommands 是配对 Execute 和 CanExecute 实现的好方法。
【解决方案3】:

ICommand 为您提供控制启用所需的 CanExecute。一个简单的委托没有。 ICommand 是要走的路。

【讨论】:

    【解决方案4】:

    显然,Microsoft 需要一个 Command 才能成为一流的东西,这可能是因为他们认为 CanExecute 对于大多数应用程序来说是必要的。我不同意并认为 CanExecute 应该只是另一个 DependencyProperty,您可以将其绑定到您的视图模型的属性,但是,嘿,我知道什么?

    他们可能还认为有必要将命令的实现与控件的数据上下文分离。再一次,这对我来说似乎没有必要,因为逻辑应该靠近正在操作的数据,这是 OO 的基本原则。

    我个人避免在 MVVM 中使用命令,因为您必须创建混乱来实现它们。我只是让视图的代码隐藏将事件委托给视图模型。

    【讨论】:

    • +1 表示视图模型上的 ICommands 比在代码隐藏中包含一些小的“中间”逻辑更多的代码/复杂性。即便如此,这种方法缺乏一个逻辑 Execute/CanExcute 配对,这在视图模型中会很好。
    【解决方案5】:

    由于此问题标题的措辞方式,读者可能会在这里寻找ICommand 的替代方法,而不仅仅是将 UI 操作直接绑定到 viewModel 的方法的方法。 (这没什么价值,因为它留下了如何处理“CanExecute”部分的问题。)

    ICommand 的使用本身是有问题的,因为它是在 Windows.Input 中定义的,这意味着为了在您的 ViewModels 中声明 ICommands,您必须从您的内部引用 WPF 和厨房水槽应用程序逻辑,一旦你这样做了,任何菜鸟都可能会注意到MessageBox 和大量其他 GUI 功能可用,并且可能开始使用它,从而导致混合应用程序逻辑和表示逻辑的混乱局面。

    所以,如果你想摆脱using System.Windows,那么你需要摆脱ICommand,如果你想摆脱ICommand,那么你可能会很高兴知道以下内容:

    WPF(特别是 XAML 设计器)不要求您的视图模型静态公开ICommand 接口的实例。

    这里的静态是指设计者不需要能够在设计期间使用反射来证明您的命令对象实现了ICommand 接口;取而代之的是,WPF在运行时检查以确保 UI 操作绑定到实际上实现 ICommand 的对象。

    因此,在您的 viewModels(应用程序逻辑)而不是 WPF 的 ICommand 接口中,您可以使用您自己设备的一些 Command 接口,您只需确保您将要实例化的类在运行时实现Command 接口也实现ICommand 以保持WPF 快乐。通过这种方式,您可以避免在 ViewModel 中包含 ICommand,随后您可以避免在应用程序逻辑中引用 System.Windows

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-30
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      • 2010-09-10
      • 2012-12-05
      相关资源
      最近更新 更多