Xaml 为什么要避免WPF MVVM模式中的代码隐藏?

Xaml 为什么要避免WPF MVVM模式中的代码隐藏?,xaml,mvvm,code-behind,Xaml,Mvvm,Code Behind,在这篇文章中,作者Josh Smith说: (1) 在设计良好的MVVM体系结构中,大多数视图的codebehind应该是空的,或者最多只包含操纵该视图中包含的控件和资源的代码。(2) 有时还需要在视图的codebehind中编写与ViewModel对象交互的代码,例如挂接事件或调用方法,否则很难从ViewModel本身调用该方法 我的问题是,在第(1)部分,为什么空的codebehind被认为是设计良好的MVVM(听起来空的codebehind总是好的) 编辑:我的问题是,如下所示,为什么像A

在这篇文章中,作者Josh Smith说:

(1) 在设计良好的MVVM体系结构中,大多数视图的codebehind应该是空的,或者最多只包含操纵该视图中包含的控件和资源的代码。(2) 有时还需要在视图的codebehind中编写与ViewModel对象交互的代码,例如挂接事件或调用方法,否则很难从ViewModel本身调用该方法

我的问题是,在第(1)部分,为什么空的codebehind被认为是设计良好的MVVM(听起来空的codebehind总是好的)

编辑:我的问题是,如下所示,为什么像
AttachedCommandBehavior
InvokeCommandAction
这样的方法试图避免代码隐藏编码。

让我详细解释一下

就第(1)项而言,我认为从目前的情况来看,情况如下。由于边框没有为
MouseRightButtonDown
实现
ICommandSource
,因此通常无法绑定事件和
ICommand
,但可以使用

但是,

我们使用下面的XAML及其codebehind的
Border\u MouseRightButtonDown
方法,该方法链接到上面提到的(2)Josh Simth

<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>

我认为如上所述使用codebehind并不坏,因为它们之间的区别仅在于绑定命令或添加事件处理程序的位置


您对此有何看法?

我认为引用的部分指的是数据可视化的方式。我认为他们的意思是,您不应该在代码背后编写代码,例如,与数据显示方式或位置相关的代码(例如:
label1.Text=…
)。使用绑定这样做可以更容易地分离设计和代码(如果在更高版本中需要在名为“tbTest”的文本框中显示数据,会发生什么情况?您必须更改代码)

他们并不是说你不应该在代码隐藏中使用任何代码——他们只是说在理想的世界中,你只会对那些本来无法处理的事件或数据做出反应


至少我从你引用的章节中了解到了这一点。

代码背后并没有什么本质上的不好之处。对于简单的情况,可以使用它。然而,在许多情况下,UI逻辑很难管理。将该逻辑封装在附加的行为和视图模型中,允许我们隔离变量(并测试它们),以便更容易理解和维护

如果要考虑可测试性,那么可以封装在viewmodels和附加行为中的UI逻辑越多,就越能够在不诉诸UI测试的情况下进行验证。(虽然它没有完全消除UI测试的需要,但它确实在进行UI测试之前提供了第一级验证,这将更加耗费时间/资源

为什么空代码隐藏被认为是设计良好的MVVM

拥有一个代码隐藏文件,该文件在其构造函数中仅包含对InitializeComponent()的调用,这意味着您已经达到了纯度-您的代码隐藏中绝对没有逻辑。您没有用任何理应属于viewmodel或model的代码污染您的视图。这意味着:

  • viewmodel(和模型)更易于单独测试
  • 您已经实现了良好的松耦合级别,从维护和可扩展性的角度来看,这具有极好的好处
当您必须更改UI时,这些好处会变得非常明显,例如从使用ListView切换到DataGrid,或者从使用标准Microsoft控件切换到使用其他供应商的控件

如前所述,有时无法避免代码隐藏文件中的一些代码。您应该确保您的代码完全与UI相关。例如,如果您有ComboA和ComboB,并且ComboB是根据ComboA中的选择而设置的,那么从视图中设置ComboB的SelectedIndex是可以的,但是对ComboB的项或SelectedItem进行绑定不是-这些属性都是数据相关的,应该通过绑定到viewmodel来指定。SelectedIndex属性直接与视觉相关,在某种程度上与实际数据无关(与viewmodel无关)

如果确实从视图中的代码隐藏访问viewmodel,则应尝试通过接口进行访问。这意味着您的viewmodel将作为接口注入或提供给视图。(请注意,绑定子系统不知道或不关心接口,它将继续以其正常方式绑定。这样做的目的是更好地编写代码,减少紧密耦合)。按照我编写代码的方式,viewmodel不知道视图是否存在,而视图只知道viewmodel是一个接口

但要记住的一点是,MVVM是一种模式,模式只是在特定情况下实现特定结果的一种方式。它不应该被视为一种宗教,非信徒或不顺从者将进入某个炼狱(尽管如果你想避免和的炼狱,遵守模式是好的)

如果您想要一个关于这个特定模式如何发挥作用的优秀示例,请尝试在ASP.Net中编写一些相当复杂的屏幕,然后在WPF或Silverlight中编写相同的屏幕,并注意其中的差异


编辑:

让我来回答你的一些问题,我希望这能有所帮助

在我的视图中,viewmodel的(视图模型)角色具有UI逻辑和视图状态

viewmodel中不应包含任何UI逻辑或“视图状态”。出于本说明的目的,我将视图状态定义为滚动位置、选定行索引、选定索引、窗口si
<Border xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseRightButtonDown">
            <i:InvokeCommandAction Command="{Binding SomeCommand}" 
               CommandParameter="A Command on MouseRightButtonDown"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Border>
<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>