代码改变世界

案例分析 BookShelf 概览(MVVM)

2010-10-31 22:38  撞破南墙  阅读(2674)  评论(7编辑  收藏  举报

1 介绍案例

2 介绍MVVM和RIA Services

  2.1MVVM

  2.2RIA Services 

3 正式开始

  3.1 目录结构

  3.2 View如何与ViewModel关联

  3.3 ViewModel如何与Model关联

  3.4 ViewModel中的Command

  3.5 不同的View之间的沟通

  3.6。。。。更多下次吧

4 相关资源  

 

1 介绍案例

该例子是来自 Kung Fu 在PDC 2010 中的 Silverlight 使用MVVM和RIA Services的一个展示 :

《Patterns and Practices with MVVM and RIA Services》

摘要:

 学习使用 RIA SERVICE 与  开发方式的结合,如 代理服务,单例责任模式?,命令方式(Command),用户互动,消息方法,子窗口,设计时的数据显示,测试和开发使用 MVVM 模式,建立一个Silverlight和WP的应用程序。

(翻译得很烂,真是英文太不好了。抱歉,附原文希望会的指正)

Learn about the rewards of using RIA Services together with development patterns, such as the Service Providers, Single Responsibility pattern, Commanding, user Interactions, Messaging, ChildWindows, Design Time Data, Testing, and developing using the Model-View-ViewModel (MVVM) pattern, to build Silverlight and Windows Phone applications. Hear the top tips you need to know for building data driven Silverlight applications that solve real world problems.

 

2 介绍下MVVM和RIA Services

 2.1 MVVM

  2.2 RIA Services

      更多参考MSDN 

    http://www.cnblogs.com/facingwaller/archive/2010/09/26/1836147.html

3 进入正题

     3.1 目录结构

   

     3.2 View如何与ViewModel关联 

 在Views文件下下面的BookView.xaml页面中的 page标签里

DataContext="{Binding Book, Source={StaticResource Locator}}"

并且F12进去可以看到 

<ResourceDictionary
         
xmlns:local="clr-namespace:BookShelf" 
         
>
    
    
<local:ViewModelLocator x:Key="Locator" />

由此可知,View和ViewModel之间通过 ViewModelLocator 来连结 

 namespace BookShelf
{
    
public class ViewModelLocator 
    {
        
private readonly ServiceProviderBase _sp;

        
public ViewModelLocator()
        {
            _sp 
= ServiceProviderBase.Instance;

            
// 1 VM for all places that use it. Just an option 一个Book的单例
            Book = new BookViewModel(_sp.PageConductor, _sp.BookDataService); 
        }

        
public BookViewModel Book { getset; }

        
// 1 new instance per View 
        public CheckoutViewModel Checkout
        {
            
get { return new CheckoutViewModel(_sp.PageConductor, _sp.BookDataService); }
        }
    }
}

 为什么需要一个ViewModelLocator来连结ViewModel 和View 呢?

   通过 ViewModelLocator 可以控制是否单例,单例的作用等下会说到。

   通过ViewModelLocator 为viewModel 提供一个 ServiceProviderBase 

那么这个ServiceProviderBase 又是做什么的呢?
 
3.3 ViewModel如何与Model关联
      ServiceProviderBase 管理所有的 数据提供的服务。
namespace BookShelf {
    
public abstract class ServiceProviderBase {
        
public virtual IPageConductor PageConductor { getprotected set; }
        
public virtual IBookDataService BookDataService { getprotected set; }

        
private static ServiceProviderBase _instance;
        
public static ServiceProviderBase Instance {
            
get { return _instance ?? CreateInstance(); }
        }

        
static ServiceProviderBase CreateInstance() {
            
// TODO:  Uncomment 判断是否在设计工具使用下
            return _instance = DesignerProperties.IsInDesignTool ?
                (ServiceProviderBase)new DesignServiceProvider() : new ServiceProvider();
        }
    }
}

 在这里他提供了基于抽象类ServiceProviderBase  的两个不同的实现。见下图

这是一个这样的模型。。类似以下的模式图 .这里有一个很好的点子就是让他可以在通过一个

 DesignerProperties.IsInDesignTool 

判断是否在设计模式下,从而使得设计模式下也可以返回数据。。。

 

  继承ServiceProviderBase是具体提供实现的IPageConductor。IBookDataService 的 类

 public class ServiceProvider : ServiceProviderBase
    {
        
public ServiceProvider()
        {
            
// Do this if you want one service for your app.
            
//PageConductor = new PageConductor(); 
        }

        
// Do this if you want one service per VM instance for your app.
        public override IPageConductor PageConductor
        {
            
get { return new PageConductor(); }
        }

        
public override IBookDataService BookDataService
        {
            
get { return new BookDataService(); }
        }
    }

 

 他的好处显而易见,

1数据服务依赖接口(从而可以切换RIA SERVICE或者 WCF SERVICE)

2易于测试
不好
1增大工作量:针对每个方法写一个接口,很多人可能无法忍受。
 

3.4 ViewModel中的Command

    继承自 RelayCommand
 RelayCommand 封装了 普通的Icommand 添了一个判断 是否 执行的参数而已。确是很好用。  
 
 3.5不同的View之间的沟通
我们可以BookView.xaml里找到EDIT 的button 然后去看
 
//Command
  public RelayCommand EditBookCommand { getset; }
//EditBookCommand 里要执行的方法
  
private void OnEditBook()
        {
            Messenger.Default.Send(new LaunchEditBookMessage() { Book = SelectedBook });
        }
//
internal class LaunchEditBookMessage : MessageBase
    {
        
public Book Book { getset; }
    }

 

 去到对应的View
 DataContext="{Binding Book, Source={StaticResource Locator}}" 
 
     
<Grid Name="grid1" DataContext="{Binding SelectedBook}">

 

 看到这里的时候你可以想象,他为什么要提供一个全局的单例,其实类似于一个全局的概念把
所有的关于BOOK的都集中到这个viewModel,当然这样做有争议,我也不知道自己的理解是否正确。
 
3.6更多
由于我不懂MVVMLight TOOLkit。有些东西不能够深入去说出来。过几天等我再认真看一下他的源码再跟大家分享。
 
 4相关资源
 我的wiki上关于 MVVM的词条 
 PPT
我整理其他的关于 MVVM的高质量的文章 部分英文加了中文注释