MVVM模板的好例子

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


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

框架/模板

  • WPF Model-View-ViewModel工具包
  • MVVM轻工具包
  • 棱镜
  • 卡利
  • 肚带
  • 有用的文章

  • 带有Model-View-ViewModel设计模式的WPF应用程序
  • .NET 3.5中的数据验证
  • 使用ViewModel提供有意义的验证错误消息
  • 基于Action的ViewModel和Model验证
  • 对话框
  • MVVM中的命令绑定
  • 不仅仅是WPF的MVC
  • MVVM + Mediator示例应用程序
  • 截屏

  • Jason Model Dolinger在Model-View-ViewModel上
  • 其他库

  • WPF门徒改进的中介模式实施(我强烈建议这个应用程序具有更复杂的导航)
  • MVVM Light Toolkit Messenger

  • 不幸的是,没有一个伟大的MVVM示例应用程序能够完成所有工作,而且还有很多不同的方法来完成任务。 首先,您可能想熟悉一个应用程序框架(Prism是一个不错的选择),因为它们为您提供诸如依赖注入,命令,事件聚合等方便的工具,以轻松地尝试适合您的不同模式。

    棱镜发布:
    http://www.codeplex.com/CompositeWPF

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

    棱镜并不一定适用于所有项目,但熟悉这一点是件好事。

    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中,该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>
    

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

    我常用的方法,不是很经典的MVVM,可以概括如下:

    一个对话框ViewModel的基类,它提供了提交和取消操作的命令,让视图知道对话已准备好关闭的事件,以及在所有对话中需要的任何其他操作。

    对话框的通用视图 - 可以是窗口,也可以是自定义“模式”叠加类型控件。 它的核心是一个内容展示者,我们将视图模型转储到其中,并处理关闭窗口的布线 - 例如,在数据上下文更改时,您可以检查新ViewModel是否从您的基类继承,如果是,订阅相关的关闭事件(处理程序将分配对话结果)。 如果您提供备用通用关闭功能(例如X按钮),则应确保在ViewModel上也运行相关的关闭命令。

    某处需要为ViewModel提供数据模板,因为它们可能非常简单,特别是因为您可能为每个对话框封装了一个单独的控件。 ViewModel的默认数据模板将如下所示:

    <DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}>
       <views:AddressEditView DataContext={Binding} />
    </DataTemplate>
    

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

    <ContentControl Content={Binding} />
    

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

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

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

    通过这种方式进行设置,ViewModel可以让应用程序打开一个对话框,并在不知道UI的情况下响应用户的操作,因此大多数情况下MVVM内核仍然完整。

    然而,有时候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
    }
    

    对话视图将绑定到位置数据,并将包含的ViewModel传递给内部ContentControl 。 ViewModel本身仍然不知道UI的任何内容。

    一般来说,我不会使用ShowDialog()方法的DialogResult return属性,也不希望线程阻塞,直到关闭对话框。 非标准的模式对话框并不总是这样工作,而在复合环境中,您通常不希望事件处理程序像这样阻止。 我更喜欢让ViewModel处理这个问题 - ViewModel的创建者可以订阅其相关事件,设置提交/取消方法等,因此不需要依赖此UI机制。

    所以,而不是这个流程:

    // in code behind
    var result = somedialog.ShowDialog();
    if (result == ...
    

    我用:

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

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


    Jason Dolinger制作了一个MVVM的好屏幕录像。 像叶戈尔提到的那样,没有一个好例子。 他们都结束了。 大多数都是很好的MVVM示例,但当您遇到复杂问题时不会。 每个人都有自己的方式。 Laurent Bugnion也有一种很好的方法来在视图模型之间进行交流。 http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch也是一个很好的例子。 Paul Stovel有一篇很好的文章,他的麦哲伦框架也解释了很多。


    你看过Caliburn吗? ContactManager示例有很多好东西。 通用的WPF示例还提供了一个很好的命令概述。 文档相当不错,论坛也很活跃。 推荐的!

    链接地址: http://www.djcxy.com/p/20277.html

    上一篇: Good examples of MVVM Template

    下一篇: WPF OpenFileDialog with the MVVM pattern?