Quantcast
Channel: KC的废墟堆 » MVVM
Viewing all articles
Browse latest Browse all 2

MVVM Doesn’t Mean Zero Code-behind

$
0
0

我在上一篇post中提到,在WPF提供的MVVM框架下,理想的情况能做到将View的逻辑只通过XAML表达,从而呈现一个zero code-behind。在不少我看过的一些相关post,StackOverflow的答案中也能明显地看出对这种zero code-behind的追求。

然而事实比我在上一篇post中提到的abstraction leak更加糟糕,迫使我不得不重新思考MVVM在WPF下的工作模式。

追求zero code-behind至少在一种情形下无法避免的会遇到一个难以优雅跨过的鸿沟:需要动态创建新的View Element,例如新窗口。

如果你需要按下一个按钮后显示一个新的窗口(无论是model还是modeless),这是无法在ViewModel层直接完成的:因为MVVM设计下,ViewModel可以知道其他的ViewModel,但是对上层的View不可知,自然也就不知道我要打开什么窗口。

我看过很多间接的solution,包括自己想到的,大致有两个方面:

  1. 通过全局的Windows Manager或者自定义接口/委托的方式进行注入,模糊掉具体的窗体类型
  2. 在ViewModel里建立相关的event handler,将相关的Command以及View上的事件捆绑,挂接到ViewModel的Event Handler里。这样可以将View的逻辑代码降低到最少。

可以注意到思路2已经开始妥协,从zero code-behind到允许least code-behind。

但是实话说,这两个思路都很不优雅,不仅繁琐,而且有时候需求变化又要做很大的改动。

于是我开始思考追求zero code-behind是否有必要。

结果是没有必要。

WPF的MVVM体系下,View层是包含code-behind的,既然碰到了“复杂”的View相关的逻辑,为什么不直接放到code-behind里呢?Zero Code-behind是很漂亮,很有诱惑,但是当你需要用大量的XAML代码加上各种拼凑的workaround去实现时,漂亮有个卵用?

于是我想到了一种干净的解决方案:View层的逻辑如果复杂,直接写在code-behind的各种事件处理里;如果过程中需要ViewModel的行为,那么ViewModel包装一个(自定义)ExecuteCommand属性,让View层访问。

仍然以前面的打开窗口为例,如果你需要打开一个编辑窗口对当前信息进行编辑,那么设计如下:

  • 按钮的事件做一些预处理
  • ViewModel暴露新建窗口需要的ViewModel为属性
  • 按钮事件访问ViewModel属性获得新建窗口的ViewModel,然后打开新窗口
  • 编辑结束后,按钮事件接着访问ViewModel提供的ExecuteCommand属性,将新建窗口的ViewModel作为参数传入执行
  • 完美收工

这样做有一个额外的好处,ViewModel更加干净,没有任何View的元素参与,更方便进行单元测试,而不用担心弹了一个窗口阻塞后续逻辑的事情发生;同时,这种做法也没有违反MVVM的单向依赖,View和ViewModel仍然只通过属性通信。

具体例子可见这里


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images