MVVM模板的好例子
我目前正在使用Microsoft MVVM模板,并发现缺乏详细的例子令人沮丧。 包含的ContactBook示例显示的命令处理非常less,而我发现的另一个示例来自MSDN杂志的文章,其中的概念相似,但使用稍微不同的方法,仍然缺乏任何复杂性。 是否有任何像样的MVVM示例,至less可以显示基本的CRUD操作和对话/内容切换?
每个人的build议都非常有用,我将开始编写一份好的资源清单
框架/模板
- WPF Model-View-ViewModel工具包
- MVVM轻工具包
- 棱镜
- 卡利
- 肚带
有用的文章
- 带有Model-View-ViewModeldevise模式的WPF应用程序
- .NET 3.5中的数据validation
- 使用ViewModel提供有意义的validation错误消息
- 基于行为的ViewModel和模型validation
- 对话框
- MVVM中的命令绑定
- 不仅仅是WPF的MVC
- MVVM + Mediator示例应用程序
截屏
- Jason Model Dolinger在Model-View-ViewModel上
额外的库
- WPF门徒改进的中介模式的实施 (我强烈build议这个应用程序有更复杂的导航)
- MVVM Light Toolkit Messenger
不幸的是,没有一个伟大的MVVM示例应用程序能够完成所有工作,而且还有很多不同的方法可以做到。 首先,你可能想要熟悉一个应用程序框架(棱镜是一个不错的select),因为它们提供了诸如dependency injection,命令,事件聚合等方便的工具来轻松地尝试适合你的不同模式。
棱镜释放:
http://www.codeplex.com/CompositeWPF
它包括一个相当不错的示例应用程序(股票交易)以及许多小例子,以及如何。 至less这是人们用MVVM实际工作的几个常见子模式的一个很好的例子。 我相信他们都有CRUD和对话的例子。
棱镜并不一定适合每个项目,但是熟悉一下是件好事。
CRUD:这个部分非常简单,WPF双向绑定使编辑大部分数据变得非常简单。 真正的诀窍是提供一个模型,可以很容易地设置用户界面。 至less要确保ViewModel(或业务对象)实现INotifyPropertyChanged
以支持绑定,并且可以将属性直接绑定到UI控件,但是您可能还需要实现IDataErrorInfo
进行validation。 通常情况下,如果您使用某种ORM解决scheme设置CRUD是一个快照。
本文演示简单的crud操作: http : //dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx
它build立在LinqToSql之上,但是与示例无关 – 所有这一切非常重要的是您的业务对象实现INotifyPropertyChanged
(由LinqToSql生成的哪些类)。 MVVM不是这个例子的要点,但是在这种情况下,我不认为这很重要。
本文演示数据validation
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx
同样,大多数ORM解决scheme生成的类已经实现了IDataErrorInfo
并且通常提供了一种机制来使添加自定义validation规则变得容易。
大多数情况下,你可以把一个ORM创build的对象(模型)包装在一个ViewModel中,该模型包含了它和命令来保存/删除 – 你可以直接将UI绑定到模型的属性上。
该视图看起来像这样(ViewModel有一个属性Item
来保存模型,就像在ORM中创build的类):
<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的基类,它提供了提交和取消操作的命令,一个事件让视图知道一个对话框已经准备好被closures,以及在你所有的对话框中需要的任何东西。
对话框的通用视图 – 可以是窗口,也可以是自定义的“模式”叠加types控件。 它的核心是一个内容展示器,我们将视图模型转储到其中,并处理closures窗口的布线 – 例如,在数据上下文更改时,您可以检查新的ViewModel是否从您的基类inheritance,如果是,订阅相关的closures事件(处理程序将分配对话结果)。 如果您提供了备用通用closuresfunction(例如Xbutton),则还应确保在ViewModel上运行相关的closures命令。
某处你需要为你的ViewModel提供数据模板,它们可以非常简单,特别是你可能有一个视图封装在单独的控件中的每个对话框。 ViewModel的默认数据模板将如下所示:
<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}> <views:AddressEditView DataContext={Binding} /> </DataTemplate>
对话视图需要访问这些对象,否则它不知道如何显示ViewModel,除了共享对话框UI之外,其内容基本上是这样的:
<ContentControl Content={Binding} />
隐式数据模板将视图映射到模型,但是谁启动它?
这是不是那么mvvm部分。 一种方法是使用全局事件。 我认为更好的做法是使用通过dependency injection提供的事件聚合器types设置 – 这样,事件对于容器是全局的,而不是整个应用程序。 Prism使用统一框架来进行容器语义和dependency injection,总的来说,我非常喜欢Unity。
通常情况下,根窗口可以订阅这个事件 – 它可以打开对话框并将其数据上下文设置为ViewModel,该ViewModel通过引发事件传入。
通过这种方式进行设置,ViewModel可以让应用程序打开一个对话框并响应那里的用户操作,而不需要了解任何有关UI的信息,因此大多数情况下MVVM内核仍然是完整的。
然而,有时候用户界面不得不提高对话框,这可能会让事情变得更加棘手。 考虑一下,例如对话框的位置取决于打开它的button的位置。 在这种情况下,当您请求打开对话框时,您需要具有一些特定于用户界面的信息。 我通常创build一个单独的类,它包含一个ViewModel和一些相关的UI信息。 不幸的是,一些耦合似乎不可避免的。
引发需要元素位置数据的对话框的button处理程序的伪代码:
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
返回属性,或期望线程阻塞,直到closures对话框。 一个非标准的模式对话框并不总是这样工作,而在一个复合环境中,你通常不希望事件处理程序像这样阻塞。 我更喜欢让ViewModel处理这个问题 – ViewModel的创build者可以订阅相关事件,设置提交/取消方法等,所以不需要依赖这个UI机制。
所以,而不是这个stream量:
// 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
我更喜欢这种方式,因为我的大部分对话框都是非阻塞的伪模式控件,这样做似乎比解决这个问题更直接。 易于unit testing。
Jason Dolinger做了MVVM的一个好屏幕录影。 就像叶戈尔提到的,没有一个好例子。 他们都结束了。 大多数MVVM都是很好的例子,但是当你遇到复杂的问题的时候就不行。 每个人都有自己的方式。 Laurent Bugnion也有很好的视图模型之间的沟通方式。 http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch也是一个很好的例子。 Paul Stovel有一个很好的post ,他的麦哲伦框架也解释了很多。
你看过Caliburn吗? ContactManager示例中有很多好东西。 通用的WPF示例还提供了一个很好的命令概述。 文件是相当不错的,论坛是积极的。 推荐的!
find这个有用的。 有代码了。
在Cinch框架中的示例项目显示了基本的CRUD和导航工具。 这是使用MVVM的一个很好的例子,并且包含了一个多部分文章来解释它的用法和动机。
我也分享了你的失望。 我正在写一个应用程序,我有这3个要求:
- 扩展
- 带有MVVM的WPF
- GPL兼容的例子
我发现的所有东西都是零碎的,所以我只是尽我所能开始写。 当我进入这个环境之后,我意识到可能会有其他人(比如你自己)可以使用一个引用应用程序,所以我将这些通用的东西重构成一个WPF / MVVM应用程序框架,并在LGPL下发布它。 我把它命名为SoapBox Core 。 如果你去下载页面,你会看到它附带一个小的演示应用程序,该演示应用程序的源代码也可以下载。 希望你觉得有帮助。 另外,如果你想要更多的信息,请发邮件给我scott {at} soapboxautomation.com。
编辑 :也张贴了一个CodeProject文章解释它是如何工作的。
即使我分担了这个挫折,直到我把这个事情交给我。 我开始IncEditor。
IncEditor( http://inceditor.codeplex.com )是一个试图向开发人员介绍WPF,MVVM和MEF的编辑器。 我开始,并设法得到一些function,如“主题”的支持。 我不是WPF或MVVM或MEF的专家,所以我不能在其中放置很多function。 我向你们诚恳地要求让你们变得更好,让像我这样的女人能更好地理解它。
在这里,我添加了使用我devise的MVVM架构的WPF(库存pipe理应用程序)应用程序的链接。
它的用户界面非常棒。 https://github.com/shivam01990/InventoryManagement
我已经从头开始编写了一个简单的MVVM示例代码项目,这里是一步一步的MVVM链接。 它从一个简单的3层架构开始,并使您使用像PRISM这样的框架。