MVVM的概念已经在脑子里渗透了一段时间,也试着使用了一段时间,就我个人理解,MVVM所倡导的应该是解耦UI跟数据打交道的那一部分,而纯UI的还是写在CodeBehind里。MVVM是以绑定(绑定数据、绑定命令)来驱动的,脱离了绑定的UI元素就没必要使用MVVM。假设一个窗口里的button作用是关掉这个窗体,如果这样一个动作都要绑到命令里去,简直就是自找麻烦。
开始MVVM之旅的第一站是实现INotifyPropertyChanged的接口的问题,虽然可以使用Prism或者MVVMLight,但是这个原理还是要懂一点的。在M里实现INotifyPropertyChanged还是在VM里实现,to be or not to be,纠结了很久。
VM其实就是V的建模,是model for view的意思,所有创建VM的时候是根据V来创建的,为V准备绑定的数据,提供暴露的属性,绑定的命令等。那么问题就来了,要使数据有通知UI的能力,就必须实现INotifyPropertyChanged,如果在M里实现,写M的人就有意见了:我的M只管我自己的逻辑,不管你UI的东东。并且,在M里实现它,如果VM里没有相应的代理属性来获取,UI就得直接绑到“属性的属性”,看起来V已经直接联系到M了。好吧,那么就在VM里实现它,这样看起来似乎清爽了,需要的话就搞M的代理属性,在代理属性里通知UI,UI直接来绑VM,这似乎更合理一点。
第二站,VM该面向什么。我上面说了一种,所有的VM都是根据V来创建,也有人说VM的创建应该面向业务,可以降低复杂性,增大复用性,因为面向M必定增加复杂性,面向V肯定降低复用性,而面向业务就能取中间的效果。目前我还是面向V,首先是因为这样简单,其次是,面向业务是可以降低复杂,增加复用,可是也是有代价的,你必须了解对项目、需求、甚至设计都十分了解,这样才能抽象出复用性很强的业务,在我没达到那个水平之前,还是老实一点。再者,没使用MVVM之前,我也没见到哪个V的CodeBehind要去用别人的CodeBehind,在我看来,VM只是把V的CodeBehind剥离出来了而已。当然,有些VM是显而易见可以复用的,那就没必要再建多建VM了,心里上感觉,内存是是有限的,能省就省吧。
第三站,数据的更新时机。一般binding使用了twoway模式,就会及时更新了,UI有什么动作,数据也跟着变,可是有时候也有这样的需求,UI需要显示地更新数据,而不是自动更新。比如我有一个窗体,上面一个文本框绑定了一个数据,和一个按钮用来关闭窗体。当我改变了文本框的内容的时候,我希望我点了关闭按钮的时候才去更新文本框绑定的数据,而不是文本框改变直接立即更新,有一种方案是UpdateSourceTrigger=Explicit,然后在后台里得到BindingExpression,再执行UpdateSource(),这样就能显示更新数据了,这样也有个小问题,UpdateSource方法是要通过控件的BindingExpression去执行的,那就得首先找到这个控件,这是很令人抓狂的,如果一个gridview里有一列是1000个checkbox,我得找到这1000个checkbox,然后再去更新,直接调用gridview的UpdateSource是不会更新里里面的控件的,不知道微软是没注意到,还是里面另有玄机我没参透 。