MVVM模板的好例子

jwa*_*ech 139 wpf mvvm

我目前正在使用Microsoft MVVM模板,并发现缺乏详细的示例令人沮丧.包含的ContactBook示例显示了非常少的命令处理,我发现的唯一其他示例来自MSDN杂志文章,其中概念类似但使用稍微不同的方法,但仍然缺乏任何复杂性.是否有任何体面的MVVM示例至少显示基本的CRUD操作和对话/内容切换?


每个人的建议都非常有用,我将开始编制一份好的资源清单

框架/模板

有用的文章

截屏

其他图书馆

Ego*_*gor 58

不幸的是,没有一个伟大的MVVM示例应用程序可以完成所有工作,并且有很多不同的方法可以做.首先,您可能希望熟悉其中一个应用程序框架(Prism是一个不错的选择),因为它们为您提供了依赖注入,命令,事件聚合等方便的工具,以便轻松尝试适合您的不同模式.

棱镜版本:http:
//www.codeplex.com/CompositeWPF

它包括一个相当不错的示例应用程序(股票交易员)以及许多较小的示例和如何做.至少它很好地演示了人们用来使MVVM实际工作的几种常见子模式.我相信他们有CRUD和对话的例子.

Prism不一定适用于每个项目,但熟悉它是一件好事.

CRUD: 这部分很简单,WPF双向绑定使编辑大多数数据变得非常容易.真正的诀窍是提供一个可以轻松设置UI的模型.至少,您希望确保ViewModel(或业务对象)实现INotifyPropertyChanged以支持绑定,并且您可以将属性直接绑定到UI控件,但您可能还希望实现IDataErrorInfo验证.通常,如果您使用某种ORM解决方案设置CRUD是一个快照.

本文演示了简单的crud操作:http: //dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

它建立在LinqToSql之上,但这与示例无关 - 所有重要的是您的业务对象实现INotifyPropertyChanged(由LinqToSql生成的类).MVVM不是那个例子的重点,但我认为在这种情况下并不重要.

本文演示数据验证
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

同样,大多数ORM解决方案生成已经实现的类,IDataErrorInfo并且通常提供一种机制,以便于添加自定义验证规则.

大多数情况下,您可以获取由某些ORM创建的对象(模型)并将其包装在保存它的ViewModel和用于保存/删除的命令中 - 并且您已准备好将UI直接绑定到模型的属性.

视图看起来像这样(ViewModel有一个Item包含模型的属性,就像在ORM中创建的类一样):

<StackPanel>
   <StackPanel DataContext=Item>
      <TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
      <TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
   </StackPanel>
   <Button Command="{Binding SaveCommand}" />
   <Button Command="{Binding CancelCommand}" />
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

对话框: 对话框和MVVM有点棘手.我更喜欢使用Mediator方法的对话框,你可以在这个StackOverflow问题中阅读更多关于它的内容:
WPF MVVM对话框示例

我常用的方法,不是很经典的MVVM,可归纳如下:

对象ViewModel的基类,用于公开提交和取消操作的命令,一个事件,让视图知道对话框已准备好关闭,以及您在所有对话框中需要的任何其他内容.

对话框的通用视图 - 可以是窗口,也可以是自定义"模态"叠加类型控件.它的核心是我们将视图模型转储到的内容呈现器,它处理关闭窗口的连接 - 例如,在数据上下文更改时,您可以检查新的ViewModel是否从您的基类继承,如果是,订阅相关的关闭事件(处理程序将分配对话框结果).如果您提供备用通用关闭功能(例如,X按钮),则还应确保在ViewModel上运行相关的关闭命令.

在某些地方,您需要为ViewModel提供数据模板,它们可以非常简单,尤其是因为您可能拥有封装在单独控件中的每个对话框的视图.ViewModel的默认数据模板将如下所示:

<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
   <views:AddressEditView DataContext="{Binding}" />
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

对话框视图需要有权访问这些,因为否则它将不知道如何显示ViewModel,除了共享对话框UI之外,其内容基本上是这样的:

<ContentControl Content="{Binding}" />
Run Code Online (Sandbox Code Playgroud)

隐式数据模板会将视图映射到模型,但谁启动它?

这是不那么mvvm的部分.一种方法是使用全局事件.我认为更好的做法是使用通过依赖注入提供的事件聚合器类型设置 - 这样事件对于容器而不是整个应用程序是全局的.Prism使用统一框架进行容器语义和依赖注入,总体来说我非常喜欢Unity.

通常,根窗口订阅此事件是有意义的 - 它可以打开对话框并将其数据上下文设置为通过引发事件传入的ViewModel.

通过这种方式进行设置,ViewModels可以让应用程序打开一个对话框并在不知道任何UI知识的情况下响应用户操作,因此大部分MVVM都保持完整.

然而,有时候UI必须引发对话框,这会使事情变得有点棘手.例如,考虑对话位置是否取决于打开它的按钮的位置.在这种情况下,当您请求打开对话框时,您需要具有一些UI特定信息.我通常创建一个单独的类来保存ViewModel和一些相关的UI信息.不幸的是,有些耦合似乎不可避免.

按钮处理程序的伪代码,用于引发需要元素位置数据的对话框:

ButtonClickHandler(sender, args){
    var vm = DataContext as ISomeDialogProvider; // check for null
    var ui_vm = new ViewModelContainer();
    // assign margin, width, or anything else that your custom dialog might require
    ...
    ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
    // raise the dialog show event
}
Run Code Online (Sandbox Code Playgroud)

对话框视图将绑定到位置数据,并将包含的ViewModel传递给内部ContentControl.ViewModel本身仍然不了解UI.

一般情况下,我不使用方法的DialogResult返回属性ShowDialog()或期望线程在对话框关闭之前阻塞.非标准模式对话框并不总是这样,在复合环境中,您通常不希望事件处理程序无论如何都要阻塞.我更喜欢让ViewModel处理这个问题 - ViewModel的创建者可以订阅它的相关事件,设置提交/取消方法等,所以不需要依赖这个UI机制.

而不是这个流程:

// in code behind
var result = somedialog.ShowDialog();
if (result == ...
Run Code Online (Sandbox Code Playgroud)

我用:

// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit 
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container
Run Code Online (Sandbox Code Playgroud)

我更喜欢这种方式,因为我的大多数对话框都是非阻塞的伪模态控件,这种做法似乎比解决它更直接.易于单元测试.

  • Mediator肯定有帮助,事件聚合器模式(Prism具有良好的实现)在低耦合是一个目标时也非常有用.此外,您的主视图模型通常具有自己的子视图模型,并且不应该与它们进行通信时出现问题.当您的子视图模型需要与您不一定了解的应用程序中的其他模块进行交互时,您需要使用中介或/和事件聚合器 - 包括UI(我的对话框示例是关于此特定情况). (2认同)

npo*_*lli 6

Jason Dolinger 对MVVM 做了一个很好的截屏视频.像叶戈尔提到的那样,没有一个很好的例子.他们都结束了.大多数都是很好的MVVM示例,但是当您遇到复杂问题时则不行.每个人都有自己的方式.Laurent Bugnion也有很好的方式在视图模型之间进行通信. http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch也是一个很好的例子.Paul Stovel有一个很好的帖子,他的Magellan框架也解释了很多.