关于wpf:MVVM模板的好例子

Good examples of MVVM Template

我目前正在使用Microsoft MVVM模板,发现缺少详细的示例令人沮丧。包含的contactbook示例显示很少的命令处理,我发现的另一个示例来自于一篇msdn杂志文章,其中的概念相似,但使用的方法略有不同,并且仍然缺乏复杂性。是否有任何像样的MVVM示例至少显示基本的CRUD操作和对话/内容切换?

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

框架/模板

  • WPF模型视图视图模型工具包
  • MVVM灯光工具包
  • 棱镜
  • 卡利本
  • 辛奇

有用文章

  • 具有模型视图和模型设计模式的WPF应用程序
  • .NET 3.5中的数据验证
  • 使用ViewModel提供有意义的验证错误消息
  • 基于动作的视图模型和模型验证
  • 对话
  • MVVM中的命令绑定
  • 不仅仅是WPF的MVC
  • MVVM+中介示例应用

屏幕截图

  • 模型视图视图模型上的Jason Dolinger

其他库

  • WPF弟子改进的中介模式实现(我强烈建议对于导航更复杂的应用程序使用此方法)
  • MVVM Light工具包信使


不幸的是,没有一个优秀的MVVM示例应用程序可以做所有的事情,而且有很多不同的方法可以做事情。首先,您可能希望熟悉现有的应用程序框架(Prism是一个不错的选择),因为它们为您提供了方便的工具,如依赖注入、命令、事件聚合等,以轻松尝试适合您的不同模式。好的。

棱镜释放:http://www.codeplex.com/compositewpf好的。

它包括一个相当不错的示例应用程序(股票交易者),以及许多小的例子和如何操作。至少它是人们用来使MVVM实际工作的几种常见子模式的一个很好的演示。我相信,他们有关于crud和dialogs的例子。好的。

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

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

本文演示了简单的CRUD操作:http://dotneslackers.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创建的对象(模型)并将其包装在一个视图模型中,该视图模型包含该对象和保存/删除命令,并且可以将UI直接绑定到模型的属性。好的。

视图应该类似这样(ViewModel有一个属性Item,用于保存模型,就像在ORM中创建的类一样):好的。

1
2
3
4
5
6
7
8
<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有点棘手。我更喜欢在对话框中使用中介方法的风格,您可以在这个stackoverflow问题中进一步了解它:WPF MVVM对话框示例好的。

我通常使用的方法不是很经典的MVVM,可以总结如下:好的。

一个对话框视图模型的基类,它公开了用于提交和取消操作的命令,一个让视图知道对话框已经准备好关闭的事件,以及在所有对话框中需要的其他内容。好的。

对话框的通用视图-可以是窗口,也可以是自定义的"模式"覆盖类型控件。其核心是我们将ViewModel转储到的内容演示者,它处理关闭窗口的连接-例如,在数据上下文更改时,您可以检查新的ViewModel是否继承自基类,如果继承,则订阅相关的Close事件(处理程序将分配对话框结果)。如果您提供了可选的通用关闭功能(例如x按钮),那么您也应该确保在ViewModel上运行相关的关闭命令。好的。

在某些地方,您需要为视图模型提供数据模板,它们可能非常简单,特别是因为您可能在单独的控件中封装了每个对话框的视图。视图模型的默认数据模板将如下所示:好的。

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

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

1
<ContentControl Content="{Binding}" />

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

这是不太重要的MVVM部分。一种方法是使用全局事件。我认为更好的做法是使用通过依赖注入提供的事件聚合器类型设置-这样,事件对于容器是全局的,而不是整个应用程序。Prism使用Unity框架进行容器语义和依赖注入,总体上我比较喜欢Unity。好的。

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

通过这种方式设置,视图模型可以要求应用程序打开一个对话框并响应用户在那里的操作,而不需要知道任何有关UI的信息,因此在大多数情况下,MVVM ness仍然是完整的。好的。

然而,有时用户界面必须提升对话框,这会使事情变得更加棘手。例如,如果对话框位置取决于打开它的按钮的位置,请考虑。在这种情况下,当您请求打开一个对话框时,需要有一些特定于用户界面的信息。我通常创建一个单独的类来保存一个视图模型和一些相关的UI信息。不幸的是,有些耦合似乎是不可避免的。好的。

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

1
2
3
4
5
6
7
8
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
}

对话框视图将绑定到位置数据,并将包含的视图模型传递到内部ContentControl。视图模型本身仍然不了解任何有关UI的信息。好的。

一般来说,我不会使用ShowDialog()方法的DialogResult返回属性,也不会期望线程在关闭对话框之前阻塞。非标准模式对话框并不总是这样工作的,而且在复合环境中,无论如何,您通常不希望事件处理程序阻塞这样的对话框。我更喜欢让视图模型处理这个问题——视图模型的创建者可以订阅它的相关事件,设置提交/取消方法等,因此不需要依赖这个UI机制。好的。

所以不是这个流程:好的。

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

我使用:好的。

1
2
3
4
5
// 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

我喜欢这种方式,因为我的大多数对话框都是非阻塞的伪模态控件,用这种方式做比处理它更简单。也易于单元测试。好的。好啊。


杰森·杜林格为MVVM制作了一个很好的剧本。就像埃戈尔提到的,没有一个好例子。他们都结束了。大多数都是很好的MVVM示例,但当您遇到复杂的问题时就不会这样。每个人都有自己的方式。LaurentBuginon也有一个很好的方法来在视图模型之间进行通信。http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx cinch也是一个很好的例子。保罗·斯托维尔有一篇很好的文章,也解释了他的麦哲伦框架。


发现这个有用。也有代码。

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx


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


我也分享了你的挫折。我在写申请书,我有三个要求:

  • 可扩展的
  • 具有MVVM的WPF
  • GPL兼容示例

我找到的只是一些零碎的东西,所以我开始尽我所能地写。在我了解了一点之后,我意识到可能还有其他人(比如你自己)可以使用一个引用应用程序,所以我将通用的东西重构成一个WPF/MVVM应用程序框架,并在LGPL下发布它。我把它命名为Soapbox Core。如果您转到下载页面,您会看到它附带了一个小的演示应用程序,并且该演示应用程序的源代码也可以下载。希望你觉得这有帮助。另外,如果您需要更多信息,请发邮件至scott soapboxautomation.com。

编辑:还发布了一篇代码项目文章来解释它是如何工作的。


Cinch框架中的示例项目显示了基本的CRUD和导航工具。这是一个使用MVVM的相当好的例子,包括一篇由多部分组成的文章,解释它的用法和动机。


我在代码项目上从头开始编写了一个简单的MVVM示例,这里是链接MVVM WPF。它从一个简单的3层体系结构开始,并使您能够使用类似棱镜的框架。

enter image description here


这里我添加了一个WPF(库存管理应用)应用程序的链接,它使用我设计的MVVM体系结构。

它的用户界面很棒。https://github.com/shivam01990/inventory管理


在我把这件事交到自己手里之前,我甚至都有同感。我开始纵火。

inceditor(http://inceditor.codeplex.com)是一个试图向开发人员介绍WPF、MVVM和MEF的编辑器。我启动了它,并设法获得了一些功能,比如"主题"支持。我不是WPF、MVVM或MEF方面的专家,所以我不能在其中加入很多功能。我真诚地请求你们把它做得更好,以便像我这样的疯子能更好地理解它。