DJ 有一个很好的答案,尽管我想在这个讨论中加入一些额外的想法。
根据我的经验,当视图不依赖于视图模型来正常运行时,视图行为(无论是代码隐藏、附加行为、混合行为还是自定义控制逻辑)通常很有用。如果视图(UserControl
、Window
、Page
等)在没有视图模型的情况下在逻辑上没有意义,则从视图中删除行为并将其移动到视图模型可能更有意义。
虽然我们可以用各种行为在阳光下做几乎任何事情,但这通常是不明智的。MVVM 有充分的理由限制了我们应该做的事情,以便我们可以观察关注点分离以提高应用程序的内聚性并解耦我们的类。这两件事就是软件可维护性的全部意义所在,随着应用程序成长为企业软件,这些概念变得越来越重要。
重要的是要考虑行为所带来的担忧。了解这一点将有助于我们找到合适的位置。以下是一些有助于了解其所属位置的问题:
行为是否与业务域模型交互(这是 MVVM 中的第一个“M”)?
对域模型具有依赖关系(甚至是松散耦合的行为)的行为应该可能属于视图模型(或服务),而不是视图。例如,如果行为需要保存到外部设备(例如数据库)或从外部设备读取,则它具有视图不应该具有的依赖关系。将此逻辑包装在服务函数中。或者,如果不使用高度分层的架构,请将其放在视图模型中。
行为是否与应用服务、领域服务、基础设施服务等交互?
出于与先前答案相同的原因,该行为可能属于视图模型或服务类。视图不应该对服务或领域模型对象有明确的了解,因为它会混淆视图所具有的职责(或关注点)。视图应该只关注用户 UI 的视觉/物理方面。许多视图应该定义一个它绑定到的契约(即视图模型接口)以便正确操作。
是否需要在相同类型的不同视图中重用该行为?
这是一个有点棘手的问题。很多时候,我们预见到能够对相同的内容进行不同的呈现。实际上,这些情况下的视图是一些结构的薄包装。例如,假设对于一个电子邮件应用程序,我们有一个接收电子邮件的汇总视图和一个详细视图。两种视图可能都需要支持相同的行为(例如删除、回复、转发)。因为我们在同一类型的不同视图中重用行为,所以行为应该属于一个共同的、可重用的地方。视图模型逻辑是一个很好的地方。
是否需要在不同类型的视图中重用该行为?
当需要在不同类型的视图(例如TextBox
, ComboBox
)中重用行为时,我们可能需要附加行为。通常,我们可以知道这一点,因为视图是如此多样化,以至于它们不可能共享一个视图模型界面。鉴于行为与视图相关的职责有关,那么自定义控制逻辑、代码隐藏、附加行为或混合行为都是合适的地方。