为什么要避免WPF MVVM模式中的代码隐藏? [英] Why to avoid the codebehind in WPF MVVM pattern?

查看:105
本文介绍了为什么要避免WPF MVVM模式中的代码隐藏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在本文中,具有模型-视图-视图模型设计模式的WPF应用程序,乔什·史密斯(Josh Smith)的作者说:

At the article, WPF Apps With The Model-View-ViewModel Design Pattern, the author who is Josh Smith said:

(1)在精心设计的MVVM体系结构中,大多数视图的背后代码应为空,或者最多仅包含操纵该视图中包含的控件和资源的代码. (2)有时也有必要在与ViewModel对象交互的View的代码隐藏中编写代码,例如,钩住事件或调用否则很难从ViewModel本身调用的方法.

(1) In a well-designed MVVM architecture, the codebehind for most Views should be empty, or, at most, only contain code that manipulates the controls and resources contained within that view. (2) Sometimes it is also necessary to write code in a View's codebehind that interacts with a ViewModel object, such as hooking an event or calling a method that would otherwise be very difficult to invoke from the ViewModel itself.

我的问题是,在(1)处,为什么将空代码隐藏视为设计良好的MVVM.(听起来,空代码隐藏总是好的.)

My question is ,at the (1), why the empty codebehind is regarded as a a well-designed MVVM.(It sounds that the empty codebehind is always good.)

以下是我的问题,为什么尝试尝试使用AttachedCommandBehaviorInvokeCommandAction之类的方法来避免代码背后的编码.

My question is, as the following, why the approach like the AttachedCommandBehavior or the InvokeCommandAction is tried to avoid the codebehind coding.

让我解释更多细节.

就(1)而言,我想从

As far as the (1) is concerned, I would think like the following situation as from the AttachedCommandBehavior. As the Border doesn't implement the ICommandSource for the MouseRightButtonDown, you cannot commonly bind the event and the ICommand, but can do with the AttachedCommandBehavior.

<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
    <local:CommandBehaviorCollection.Behaviors>
           <local:BehaviorBinding Event="MouseRightButtonDown" 
                  Command="{Binding SomeCommand}" 
                  CommandParameter="A Command on MouseRightButtonDown"/>
    </local:CommandBehaviorCollection.Behaviors>
</Border>

OR

我们可以使用System.Windows.Interactivity.InvokeCommandAction来做到这一点.

We can do this with the System.Windows.Interactivity.InvokeCommandAction.

<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>

但是,

我们在下面的XAML及其代码后边使用Border_MouseRightButtonDown方法,该方法与上述(2)Josh Simth链接.

We use the following XAML and its codebehind having the Border_MouseRightButtonDown method, which is linked to the (2) Josh Simth said above.

<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>

我认为使用上面的代码并不是很糟糕,因为它们之间的区别仅在于绑定命令或添加事件处理程序的地方.

I think using the codebehind as above is not bad just because the difference between these is only where binding a command or add event handler is.

您对此有何看法?

推荐答案

为什么后面的空代码被认为是设计良好的MVVM

why the empty codebehind is regarded as a a well-designed MVVM

在其构造函数中包含一个仅由对InitializeComponent()的调用组成的代码隐藏文件意味着您已经达到了纯净—您的代码背后逻辑绝对为零.您尚未使用正确属于viewmodel或模型的任何代码污染视图.这意味着几件事:

Having a code-behind file which consists solely of a call to InitializeComponent() in its constructor means you have achieved purity - you have absolutely zero logic in your codebehind. You have not polluted your view with any code that rightfully belongs in the viewmodel or model. This means a couple of things:

  • viewmodel(和模型)更易于单独测试
  • 您已经达到了良好的松散耦合水平,从维护和可扩展性的角度来看,这具有出色的优势

当您必须更改UI(即从使用ListView切换到DataGrid,或者从使用标准的Microsoft控件更改为使用其他供应商的控件)时,好处真正变得明显.

The benefits really become noticeable when you have to change your UI, i.e. you switch from using a ListView to a DataGrid, or you change from using the standard Microsoft controls to using some other vendor's.

但是,如上所述,有时无法避免代码隐藏文件中包含一些代码.您应该确保的是,您所拥有的代码纯粹是与UI相关的.例如,如果您具有ComboA和ComboB,并且响应于ComboA中的选择而设置了ComboB,则从视图中设置ComboB的SelectedIndex很好,但是不设置ComboB的Items或SelectedItem-这些属性是这两个数据都是相关的,应该通过绑定到视图模型来指定. SelectedIndex属性与视觉直接相关,并且在某种程度上与实际数据无关(与视图模型无关).

As mentioned though, it is sometimes impossible to avoid a little code in the code-behind file. What you should ensure is that the code you do have is purely UI related. As an example, if you have ComboA and ComboB, and ComboB is set in response to the selection in ComboA, then setting the SelectedIndex of ComboB from the view is fine, but setting the Items or the SelectedItem of ComboB is not - those properties are both data related and should be specified via binding to the viewmodel. The SelectedIndex property is directly visual related and somewhat independent of the actual data (and it is irrelevant to the viewmodel).

如果确实从视图中的代码隐藏访问视图模型,则应尝试通过接口进行操作.这意味着您的视图模型将作为接口注入或提供给视图. (请注意,绑定子系统不了解或不关心接口,它将继续以其常规方式进行绑定.这实现的是更好的代码,并且耦合性降低了).按照我的编码方式,viewmodel不知道视图存在,并且该视图仅知道该viewmodel作为接口.

If you do access the viewmodel from code-behind in the view, you should try and do it via an interface. This means your viewmodel is injected or given to the view as an interface. (Note that the binding subsystem doesn't know or care about the interface, it will continue to bind in its normal way. What this achieves is better code, with less tight coupling). The way I code it, the viewmodel has no idea that a view exists, and the view only knows about the viewmodel as an interface.

要记住的一件事是MVVM是一种模式,而模式只是配方或处方,以在特定情况下达到特定效果.它不应该被视为一种宗教,在这里非信徒或不信教者会去炼狱(尽管如果您想避免代码异味).

One thing to remember though is that MVVM is a pattern, and a pattern is simply a recipe or prescription for achieving a certain result in a certain situation. It shouldn't be treated as a religion, where non-believers or non-conformers are going to go to some purgatory (although adherence to the pattern is good if you want to avoid the purgatory of maintenance hell and code smell).

如果您想要一个很好的例子来说明这种特定模式如何提供帮助,请尝试在ASP.Net中编写一些相当复杂的屏幕,然后在WPF或Silverlight中编写相同的屏幕,并注意区别.

If you want an excellent example of how this particular pattern helps, try writing a few reasonably complicated screens in ASP.Net, and then write the same in WPF or Silverlight, and note the difference.

让我回答您的一些问题,希望对您有所帮助....

let me answer some of your questions, I hope it helps....

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

the viewmodel's (model of view) role , in my view, has UI logic and state of a view

viewmodel中永远不应包含任何UI逻辑或视图状态".为了便于说明,我将视图状态定义为滚动位置,选定的行索引,选定的索引,窗口大小等.诸如SelectedIndex之类的事情特定于在UI中显示数据的方式(如果您更改了DataGrid的排序顺序,则即使SelectedItem仍然相同,SelectedIndex也可以更改).在这种特殊情况下,可以将SelectedItem绑定到视图模型,但不能绑定SelectedIndex.
如果您需要跟踪UI会话类型信息,则应该提出一些通用的内容(例如,在将重要内容保存到KeyValuePair列表之前,我一直保持视图状态),然后通过调用保存" viewmodel(通过我之前提到的接口).视图不知道如何保存数据,视图模型也不知道数据来自视图(它只是通过其接口公开了调用).

The viewmodel should never have any UI logic or "view state" in it. For the purposes of this explanation, I would define view state as scroll position, selected row index, selected index, window size, etc. None of those belong in the viewmodel; things like SelectedIndex are specific to the way the data is shown in the UI (if you change the sort order of a DataGrid then the SelectedIndex can change, even though the SelectedItem is still the same). In this particular case, the SelectedItem can be bound to the viewmodel, but the SelectedIndex shouldn't.
If you need to keep track of UI session type info them then you should come up with something generic (for example, I have persisted view state before by saving important stuff into a KeyValuePair list) which is then "saved" with a call to the viewmodel (via the interface I mentioned previously). The view has no idea how the data is being saved, and the viewmodel has no idea the data is coming from a view (it has simply exposed a call through its interface).

视图的作用是显示一些内容并同步视图模型(具有数据绑定代码)

and the view's role is displaying some contents and synchronizing the viewmodel(having databinding code)

是的,视图的职责只是可视地显示视图模型提供的数据. viewmodel从模型中获取数据(该模型负责进行数据库调用或WCF Web服务调用,这通常是通过服务"完成的,但这是另外一个完整的讨论).然后,视图模型可以对数据进行整形或处理,即,它可以获取所有客户的列表,但只能在该视图可以绑定到的公共属性中公开该列表的过滤版本(可能是当前客户).
如果要将数据处理为视觉对象(一个常见的示例是将枚举值转换为颜色),则视图模型仍然仅具有枚举值,并且视图仍绑定到该值,但是视图也使用转换器将纯数据转换为可视表示形式.通过使用转换器,视图模型仍然避免执行任何与UI相关的操作,并且视图避免了任何实际的逻辑.

Yes, the view's responsibility is simply to visually display data presented by the viewmodel. The viewmodel gets the data from the model (the model is responsible for making database calls or WCF webservice calls, this will usually be done via a "service", but that is a whole other discussion). The viewmodel can then shape or manipulate the data, i.e. it may get a list of all customers, but only expose a filtered version of that list (maybe the current customers) in a public property which the view can then bind to.
If the data is to be manipulated into something visual (a common example is an enum value being translated into a color), then the viewmodel still only has the enum value(s), and the view still binds to that value, but the view also uses a converter to translate the pure data to a visual representation. By using the converter the viewmodel has still avoided doing anything UI related, and the view has avoided any real logic.

这篇关于为什么要避免WPF MVVM模式中的代码隐藏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆