MVVM模板的好例子 [英] Good examples of MVVM Template

查看:63
本文介绍了MVVM模板的好例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用Microsoft MVVM模板,发现缺少详细的示例令人沮丧.包含的ContactBook示例仅显示很少的命令处理,而我发现的唯一另一个示例是从MSDN Magazine文章中获得的,该示例的概念相似,但使用的方法略有不同,但仍然没有任何复杂性.是否有任何不错的MVVM示例,至少显示了基本的CRUD操作和对话框/内容切换?

I am currently working with the Microsoft MVVM template and find the lack of detailed examples frustrating. The included ContactBook example shows very little Command handling and the only other example I've found is from an MSDN Magazine article where the concepts are similar but uses a slightly different approach and still lack in any complexity. Are there any decent MVVM examples that at least show basic CRUD operations and dialog/content switching?

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

Everyone's suggestions were really useful and I will start compiling a list of good resources

框架/模板

  • WPF Model-View-ViewModel Toolkit
  • MVVM Light Toolkit
  • Prism
  • Caliburn
  • Cinch

有用的文章

  • WPF Apps With The Model-View-ViewModel Design Pattern
  • Data Validation in .NET 3.5
  • Using a ViewModel to Provide Meaningful Validation Error Messages
  • Action based ViewModel and Model validation
  • Dialogs
  • Command Bindings in MVVM
  • More than just MVC for WPF
  • MVVM + Mediator Example Application

截屏视频

其他库

  • WPF Disciples' improved Mediator Pattern implementation(I highly recommend this for applications that have more complex navigation)
  • MVVM Light Toolkit Messenger

推荐答案

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

Unfortunately there is no one great MVVM example app that does everything, and there are a lot of different approaches to doing things. First, you might want to get familiar with one of the app frameworks out there (Prism is a decent choice), because they provide you with convenient tools like dependency injection, commanding, event aggregation, etc to easily try out different patterns that suit you.

棱镜释放:
http://www.codeplex.com/CompositeWPF

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

It includes a pretty decent example app (the stock trader) along with a lot of smaller examples and how to's. At the very least it's a good demonstration of several common sub-patterns people use to make MVVM actually work. They have examples for both CRUD and dialogs, I believe.

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

Prism isn't necessarily for every project, but it's a good thing to get familiar with.

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

CRUD: This part is pretty easy, WPF two way bindings make it really easy to edit most data. The real trick is to provide a model that makes it easy to set up the UI. At the very least you want to make sure that your ViewModel (or business object) implements INotifyPropertyChanged to support binding and you can bind properties straight to UI controls, but you may also want to implement IDataErrorInfo for validation. Typically, if you use some sort of an ORM solution setting up CRUD is a snap.

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

This article demonstrates simple crud operations: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

它基于LinqToSql构建,但这与示例无关-重要的是您的业务对象实现INotifyPropertyChanged(由LinqToSql生成的类可以实现). MVVM不是该示例的重点,但在这种情况下,我认为这无关紧要.

It is built on LinqToSql, but that is irrelevant to the example - all that is important is that your business objects implement INotifyPropertyChanged (which classes generated by LinqToSql do). MVVM is not the point of that example, but I don't think it matters in this case.

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

This article demonstrates data validation
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

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

Again, most ORM solutions generate classes that already implement IDataErrorInfo and typically provide a mechanism to make it easy to add custom validation rules.

大多数时候,您可以将某些ORM创建的对象(模型)包装到一个包含有该对象和用于保存/删除命令的ViewModel中,并且可以将UI直接绑定到模型的属性.

Most of the time you can take an object(model) created by some ORM and wrap it in a ViewModel that holds it and commands for save/delete - and you're ready to bind UI straight to the model's properties.

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

The view would look like something like this (ViewModel has a property Item that holds the model, like a class created in the 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对话框示例

Dialogs: Dialogs and MVVM are a bit tricky. I prefer to use a flavor of the Mediator approach with dialogs, you can read a little more about it in this StackOverflow question:
WPF MVVM dialog example

我通常的方法(不是很经典的MVVM)可以总结如下:

My usual approach, which is not quite classic MVVM, can be summarized as follows:

对话框ViewModel的基类,它公开用于提交和取消操作的命令,一个事件使视图知道对话框已准备就绪,可以关闭,以及所有其他对话框中需要的东西.

A base class for a dialog ViewModel that exposes commands for commit and cancel actions, an event to lets the view know that a dialog is ready to be closed, and whatever else you will need in all of your dialogs.

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

A generic view for your dialog - this can be a window, or a custom "modal" overlay type control. At its heart it is a content presenter that we dump the viewmodel into, and it handles the wiring for closing the window - for example on data context change you can check if the new ViewModel is inherited from your base class, and if it is, subscribe to the relevant close event (the handler will assign the dialog result). If you provide alternative universal close functionality (the X button, for instance), you should make sure to run the relevant close command on the ViewModel as well.

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

Somewhere you need to provide data templates for your ViewModels, they can be very simple especially since you probably have a view for each dialog encapsulated in a separate control. The default data template for a ViewModel would then look something like this:

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

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

The dialog view needs to have access to these, because otherwise it won't know how to show the ViewModel, aside from the shared dialog UI its contents are basically this:

<ContentControl Content="{Binding}" />

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

The implicit data template will map the view to the model, but who launches it?

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

This is the not-so-mvvm part. One way to do it is to use a global event. What I think is a better thing to do is to use an event aggregator type setup, provided through dependency injection - this way the event is global to a container, not the whole app. Prism uses the unity framework for container semantics and dependency injection, and overall I like Unity quite a bit.

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

Usually, it makes sense for the root window to subscribe to this event - it can open the dialog and set its data context to the ViewModel that gets passed in with a raised event.

通过这种方式进行设置,ViewModels可以在不了解UI的情况下要求应用程序打开对话框并在其中响应用户操作,因此在大多数情况下MVVM保持完整.

Setting this up in this way lets ViewModels ask the application to open a dialog and respond to user actions there without knowing anything about the UI so for the most part the MVVM-ness remains complete.

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

There are times, however, where the UI has to raise the dialogs, which can make things a bit trickier. Consider for example, if the dialog position depends on the location of the button that opens it. In this case you need to have some UI specific info when you request a dialog open. I generally create a separate class that holds a ViewModel and some relevant UI info. Unfortunately some coupling seems unavoidable there.

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

Pseudo code of a button handler that raises a dialog which needs element position data:

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一无所知.

The dialog view will bind to position data, and pass the contained ViewModel to the inner ContentControl. The ViewModel itself still doesn't know anything about the UI.

通常,我不使用ShowDialog()方法的DialogResult返回属性,或者期望线程在对话框关闭之前阻塞.非标准的模态对话框并不总是那样工作,在复合环境中,您通常通常不希望事件处理程序那样阻塞.我更喜欢让ViewModels处理-ViewModel的创建者可以订阅其相关事件,设置commit/cancel方法等,因此无需依赖此UI机制.

In general I don't make use of the DialogResult return property of the ShowDialog() method or expect the thread to block until the dialog is closed. A non-standard modal dialog doesn't always work like that, and in a composite environment you often don't really want an event handler to block like that anyhow. I prefer to let the ViewModels deal with this - the creator of a ViewModel can subscribe to its relevant events, set commit/cancel methods, etc, so there is no need to rely on this UI mechanism.

所以不是这个流程:

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

我更喜欢这种方式,因为我的大多数对话框都是非阻塞的伪模式控件,与解决该问题相比,这种方式似乎更简单.单元测试也很容易.

I prefer it this way because most of my dialogs are non-blocking pseudo-modal controls and doing it this way seems more straightforward than working around it. Easy to unit test as well.

这篇关于MVVM模板的好例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆