MVVM 模板的好例子

我目前的工作与微软 MVVM 模板,并发现缺乏详细的例子令人沮丧。所包含的 ContactBook 示例显示了很少的 Command 处理,我发现的另一个示例来自 MSDN Magazine 的一篇文章,其中的概念相似,但使用了略有不同的方法,仍然缺乏任何复杂性。是否有任何像样的 MVVM 示例至少显示基本的 CRUD 操作和对话框/内容切换?


每个人的建议都很有用,我将开始整理一份好资源的清单

框架/模板

有用文章

视频

增设图书馆

70651 次浏览

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

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

我也分享了你的沮丧。我正在写一份申请,我有3个要求:

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

我只找到一些零零碎碎的东西,所以我就开始尽我所能地写下来。在我深入了解之后,我意识到可能还有其他人(比如你自己)可以使用参考应用程序,所以我将通用的东西重构成 WPF/MVVM 应用程序框架,并在 LGPL 下发布它。我把它命名为 肥皂盒核心。如果您进入下载页面,您将看到它附带了一个小的演示应用程序,并且该演示应用程序的源代码也可以下载。希望对你有帮助。另外,如果你想了解更多信息,可以发邮件到 scott { at } soapboxautomation.com 给我。

编辑 : 也发布了一个 CodeProject 文章解释它是如何工作的。

不幸的是,没有一个伟大的 MVVM 示例应用程序可以做所有的事情,而且有很多不同的方法来做事情。首先,你可能需要熟悉其中一个应用框架(Prism 是一个不错的选择) ,因为它们为你提供了方便的工具,比如依赖注入、指挥、事件聚合等,可以轻松地尝试适合你的不同模式。

棱镜释放:
Http://www.codeplex.com/compositewpf

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

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

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

这篇文章展示了简单的脏操作: Http://dotnetslackers.com/articles/wpf/wpfdatabindingwithlinq.aspx

它是基于 LinqToSql 构建的,但这与示例无关——重要的是您的业务对象实现 INotifyPropertyChanged(由 LinqToSql 生成的类实现 INotifyPropertyChanged)。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 上也运行相关的 close 命令。

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

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

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

<ContentControl Content="{Binding}" />

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

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

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

通过这种方式设置,ViewModel 可以要求应用程序打开一个对话框,并在不了解 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
}

对话框视图将绑定到位置数据,并将包含的 ViewModel 传递给内部 ContentControl。ViewModel 本身对 UI 仍然一无所知。

一般来说,我不会使用 ShowDialog()方法的 DialogResult返回属性,也不会期望线程在对话框关闭之前阻塞。非标准模式对话框并不总是这样工作,而且在复合环境中,您通常不希望事件处理程序像这样阻塞。我更喜欢让 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

我更喜欢这种方式,因为我的大多数对话框都是非阻塞伪模态控件,这样做似乎比绕过它更简单。也容易进行单元测试。

杰森杜林杰做了一个很好的 视频的 MVVM。就像埃戈尔提到的,没有一个好的例子。到处都是。大多数都是很好的 MVVM 示例,但是当您遇到复杂的问题时就不是了。每个人都有自己的方式。Laurent Bugnion 也有一个很好的视图模型之间的交流方式。Cinch 也是一个很好的例子。Paul Stovel 有一个很好的 邮寄,用他的麦哲伦框架解释了很多东西。

甚至我也分担了这种沮丧,直到我把这件事交到自己手里。

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

发现这个很有用,还有密码。

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

在这里我增加了一个使用 MVVM 架构由我设计的 WPF (库存管理应用程序)应用程序的链接。

它的用户界面很棒。 Https://github.com/shivam01990/inventorymanagement

我已经写了一个简单的 MVVM 示例从头开始的代码项目,这里是链接 一步一步来。 它从一个简单的3层体系结构开始,逐步让您使用一些像 PRISM 这样的框架。

enter image description here