稳扎稳打Silverlight(58) - 4.0通信之WCF RIA Services: 通过 Domain Service, 以 MVVM 模式实现数据的添加、删除、修改和查询

[索引页]
[源码下载]


稳扎稳打Silverlight(58) - 4.0通信之WCF RIA Services: 通过 Domain Service, 以 MVVM 模式实现数据的添加、删除、修改和查询



作者:webabcd


介绍
Silverlight 4.0 之 WCF RIA Services:DomainService 和 MVVM


在线DEMO
http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html


示例
演示如何通过 Domain Service, 以 MVVM 模式实现数据的添加、删除、修改和查询
1、服务端
MyDomainService.cs

代码
/*
 * 一个 Domain Service 服务
 
*/

namespace  Silverlight40.Web.Service
{
    
using  System;
    
using  System.Collections.Generic;
    
using  System.ComponentModel;
    
using  System.ComponentModel.DataAnnotations;
    
using  System.Data;
    
using  System.Linq;
    
using  System.ServiceModel.DomainServices.EntityFramework;
    
using  System.ServiceModel.DomainServices.Hosting;
    
using  System.ServiceModel.DomainServices.Server;
    
using  Silverlight40.Web.Model;

    
/*
     * 用 LinqToEntities 实现 Domain Service 则继承 LinqToSqlDomainService<NorthwindEntities>;用 LinqToSql 实现 Domain Service 则继承 LinqToSqlDomainService<NorthwindEntities>
     * Domain Service 内所有对客户端可见的方法都应该是 public 的,Domain Service 内的方法不支持重载
     * 对客户端可见的方法要满足命名约定,或为其指定对应的 Attribute。当前支持 6 种数据操作:Query, Update, Insert, Delete, Invoke, Named Update, 详见文档
     * 
     * [EnableClientAccess()] - 该类对客户端可见
     * [EnableClientAccess(RequiresSecureEndpoint = true)] - 使用 HTTPS 协议
     * [Ignore] - 指定的方法不作为服务而公开
     * [Query(IsComposable=true)] - 支持客户端的 linq 查询,而且此查询会被在服务端执行
     * 
     * 在多个 Domain Services 间共享实体:通过 [ExternalReference], [Association()], Context.AddReference() 实现,详见文档
     
*/

    
//  服务端的类名为:MyDomainService,则其生成的客户端上下文的类名为:MyDomainContext
    [EnableClientAccess()]
    
public   class  MyDomainService : LinqToEntitiesDomainService < NorthwindEntities >
    {
        [Query(IsDefault 
=   true )]
        
public  IQueryable < Category >  GetCategories()
        {
            
return   this .ObjectContext.Categories;
        }

        
public   void  InsertCategory(Category category)
        {
            
if  ((category.EntityState  !=  EntityState.Detached))
            {
                
this .ObjectContext.ObjectStateManager.ChangeObjectState(category, EntityState.Added);
            }
            
else
            {
                
this .ObjectContext.Categories.AddObject(category);
            }
        }

        
public   void  UpdateCategory(Category currentCategory)
        {
            
this .ObjectContext.Categories.AttachAsModified(currentCategory,  this .ChangeSet.GetOriginal(currentCategory));
        }

        
public   void  DeleteCategory(Category category)
        {
            
if  ((category.EntityState  ==  EntityState.Detached))
            {
                
this .ObjectContext.Categories.Attach(category);
            }
            
this .ObjectContext.Categories.DeleteObject(category);
        }



        [Query(IsDefault 
=   true )]
        
public  IQueryable < Product >  GetProducts()
        {
            
return   this .ObjectContext.Products;
        }

        
public  IQueryable < Product >  GetProductsBySort( string  sort)
        {
            
return  ObjectContext.Products.OrderBy(sort);
        }

        
public   void  InsertProduct(Product product)
        {
            
if  ((product.EntityState  !=  EntityState.Detached))
            {
                
this .ObjectContext.ObjectStateManager.ChangeObjectState(product, EntityState.Added);
            }
            
else
            {
                
this .ObjectContext.Products.AddObject(product);
            }
        }

        
public   void  UpdateProduct(Product currentProduct)
        {
            
this .ObjectContext.Products.AttachAsModified(currentProduct,  this .ChangeSet.GetOriginal(currentProduct));
        }

        
public   void  DeleteProduct(Product product)
        {
            
if  ((product.EntityState  ==  EntityState.Detached))
            {
                
this .ObjectContext.Products.Attach(product);
            }
            
this .ObjectContext.Products.DeleteObject(product);
        }

        
public  IQueryable < Product >  GetProductsByCategoryId( int  categoryId)
        {
            
return   this .ObjectContext.Products.Where(p  =>  p.CategoryID  ==  categoryId);
        }
    }
}



MyDomainService.metadata.cs

代码
/*
 * [MetadataTypeAttribute()] - 指定类的元数据对象
 * [Include] - 生成的客户端上下文包含此字段
 * [Exclude] - 生成的客户端上下文不包含此字段
 * [Composition] - 指定字段为关联数据,即父实体增删改查时,此关联数据也会做相应的变化。指定此 Attribute 后,需显式指定其为 [Include]
 * [Editable(true)], [Editable(false)] - 指定字段是否可编辑
 
*/

namespace  Silverlight40.Web.Model
{
    
using  System;
    
using  System.Collections.Generic;
    
using  System.ComponentModel;
    
using  System.ComponentModel.DataAnnotations;
    
using  System.Data.Objects.DataClasses;
    
using  System.Linq;
    
using  System.ServiceModel.DomainServices.Hosting;
    
using  System.ServiceModel.DomainServices.Server;

    [MetadataTypeAttribute(
typeof (Category.CategoryMetadata))]
    
public   partial   class  Category
    {
        
internal   sealed   class  CategoryMetadata
        {
            
private  CategoryMetadata()
            {
            }

            [Key()]
            
public   int  CategoryID {  get set ; }

            [Display(Name 
=   " 类别名称 " )]  //  显示用
             public   string  CategoryName {  get set ; }

            
public   string  Description {  get set ; }

            [Exclude]
            
public   byte [] Picture {  get set ; }

            [Include]
            
//  [Composition]
             public  EntityCollection < Product >  Products {  get set ; }
        }
    }

    [MetadataTypeAttribute(
typeof (Product.ProductMetadata))]
    
public   partial   class  Product
    {
        
internal   sealed   class  ProductMetadata
        {
            
private  ProductMetadata()
            {
            }

            
public  Category Category {  get set ; }

            
public  Nullable < int >  CategoryID {  get set ; }

            
public   bool  Discontinued {  get set ; }

            
public  EntityCollection < Order_Detail >  Order_Details {  get set ; }

            [Display(Order 
=   0 , Name  =   " 产品ID " )]
            
public   int  ProductID {  get set ; }

            [Display(Order 
=   1 , Name  =   " 产品名称 " )]
            
public   string  ProductName {  get set ; }

            
public   string  QuantityPerUnit {  get set ; }

            
public  Nullable < short >  ReorderLevel {  get set ; }

            
public  Supplier Supplier {  get set ; }

            
public  Nullable < int >  SupplierID {  get set ; }

            
public  Nullable < decimal >  UnitPrice {  get set ; }

            
public  Nullable < short >  UnitsInStock {  get set ; }

            
public  Nullable < short >  UnitsOnOrder {  get set ; }
        }
    }
}



2、客户端
ProductViewModel.cs

代码
/*
 * 演示:通过 Domain Service, 以 MVVM 模式实现数据的添加、删除、修改和查询
 * 此类为 MVVM 中的 ViewModel
 
*/

using  System;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Ink;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;

using  Silverlight40.Web.Model;
using  System.Collections.ObjectModel;
using  Silverlight40.Web.Service;
using  System.ComponentModel;
using  System.ServiceModel.DomainServices.Client;
using  System.Collections.Generic;

namespace  Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
    
public   class  ProductViewModel
    {
        
public  ObservableCollection < Product >  Data {  get set ; }
       
        
private  MyDomainContext _context;

        
public  ProductViewModel()
        {
            Data 
=   new  ObservableCollection < Product > ();

            LoadData();
        }

        
private   void  LoadData()
        {
            _context 
=   new  MyDomainContext();

            EntityQuery
< Product >  query  =  _context.GetProductsQuery().OrderByDescending(p  =>  p.ProductID);

            
/*
             * System.ServiceModel.DomainServices.Client.LoadOperation - 用于异步加载
             * System.ServiceModel.DomainServices.Client.InvokeOperation - 用于异步调用
             * System.ServiceModel.DomainServices.Client.SubmitOperation - 用于异步提交
             
*/

            LoadOperation
< Product >  lo  =  _context.Load(query);

            lo.Completed 
+=   delegate
            {
                Data.Clear();
                
foreach  (Product p  in  lo.Entities)
                {
                    Data.Add(p);
                }
            };
        }


        
public  ICommand FilterCommand
        {
            
get  {  return   new  FilterCommand( this ); }
        }
        
public  ICommand InsertCommand
        {
            
get  {  return   new  InsertCommand( this ); }
        }
        
public  ICommand DeleteCommand
        {
            
get  {  return   new  DeleteCommand( this ); }
        }
        
public  ICommand UpdateCommand
        {
            
get  {  return   new  UpdateCommand( this ); }
        }


        
//  检索数据
         public   void  Filter( string  productName)
        {
            EntityQuery
< Product >  query  =  _context.GetProductsQuery().Where(p  =>  p.ProductName.Contains(productName));

            LoadOperation
< Product >  lo  =  _context.Load(query);

            lo.Completed 
+=   delegate
            {
                Data.Clear();

                
foreach  (Product p  in  lo.Entities)
                {
                    Data.Add(p);
                }
            };
        }

        
        
//  插入数据
         public   void  Insert( string  productName)
        {            
            EntitySet
< Product >  products  =  _context.EntityContainer.GetEntitySet < Product > ();
            Product product 
=   new  Product();
            product.ProductName 
=  productName;
            product.CategoryID 
=   1 ;
            product.SupplierID 
=   1 ;
            products.Add(product);

            _context.SubmitChanges(OnInsertCompleted, product);
        }
        
private   void  OnInsertCompleted(SubmitOperation so)    
        {
            
if  ( ! so.HasError)
            {
                Data.Insert(
0 , so.UserState  as  Product);
            }
        }


        
//  删除数据
         public   void  Delete(List < Product >  products)
        {
            EntitySet
< Product >  productsOriginal  =  _context.EntityContainer.GetEntitySet < Product > ();
            
foreach  (Product product  in  products)
            {
                productsOriginal.Remove(product);
            }

            _context.SubmitChanges(OnDeleteCompleted, products);
        }
        
private   void  OnDeleteCompleted(SubmitOperation so)
        {
            
if  ( ! so.HasError)
            {
                List
< Product >  products  =  so.UserState  as  List < Product > ;
                
foreach  (Product product  in  products)
                {
                    Data.Remove(product);
                }
            }
        }


        
//  更新数据
         public   void  Update()
        {
            _context.SubmitChanges(OnUpdateCompleted, 
null );
        }
        
private   void  OnUpdateCompleted(SubmitOperation so)
        {
            
if  ( ! so.HasError)
            {
                MessageBox.Show(
" 更新成功 " );
            }
        }
    }
}


InsertCommand.cs

代码
using  System;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Ink;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;

namespace  Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
    
///   <summary>
    
///  插入的 Command
    
///   </summary>
     public   class  InsertCommand : ICommand
    {
        
private  ProductViewModel _viewModel;

        
public  InsertCommand(ProductViewModel viewModel)
        {
            _viewModel 
=  viewModel;
        }

        
public   bool  CanExecute( object  parameter)
        {
            
return   true ;
        }

        
public   event  EventHandler CanExecuteChanged;

        
//  参数为:productName
         public   void  Execute( object  parameter)
        {
            var productName 
=  ( string )parameter;
            _viewModel.Insert(productName);
        }
    }
}


DeleteCommand.cs

代码
using  System;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Ink;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;

using  Silverlight40.Web.Model;
using  System.Collections.Generic;

namespace  Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
    
///   <summary>
    
///  删除的 Command
    
///   </summary>
     public   class  DeleteCommand  : ICommand
    {
        
private  ProductViewModel _viewModel;

        
public  DeleteCommand(ProductViewModel viewModel)
        {
            _viewModel 
=  viewModel;
        }

        
public   bool  CanExecute( object  parameter)
        {
            
return   true ;
        }

        
public   event  EventHandler CanExecuteChanged;

        
//  参数为:DataGrid.SelectedItems [System.Collections.IList 类型]
         public   void  Execute( object  parameter)
        {
            var collection 
=  parameter  as  System.Collections.IList;
            var products 
=   new  List < Product > ();

            
foreach  (Product product  in  collection)
            {
                products.Add(product);
            }

            _viewModel.Delete(products);
        }
    }
}


UpdateCommand.cs

代码
using  System;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Ink;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;

namespace  Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
    
///   <summary>
    
///  更新的 Command
    
///   </summary>
     public   class  UpdateCommand : ICommand
    {
        
private  ProductViewModel _viewModel;

        
public  UpdateCommand(ProductViewModel viewModel)
        {
            _viewModel 
=  viewModel;
        }

        
public   bool  CanExecute( object  parameter)
        {
            
return   true ;
        }

        
public   event  EventHandler CanExecuteChanged;

        
public   void  Execute( object  parameter)
        {
            _viewModel.Update();
        }
    }
}


FilterCommand.cs

代码
using  System;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Ink;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;

namespace  Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
    
///   <summary>
    
///  查询的 Command
    
///   </summary>
     public   class  FilterCommand : ICommand
    {
        
private  ProductViewModel _viewModel;

        
public  FilterCommand(ProductViewModel viewModel)
        {
            _viewModel 
=  viewModel;
        }

        
public   bool  CanExecute( object  parameter)
        {
            
return   true ;
        }

        
public   event  EventHandler CanExecuteChanged;

        
//  参数为:productName
         public   void  Execute( object  parameter)
        {
            var productName 
=  ( string )parameter;
            _viewModel.Filter(productName);
        }
    }
}
 


Demo.xaml

代码
< navigation:Page  x:Class ="Silverlight40.WCFRIAServices.DomainServiceAndMVVM.Demo"  
           xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
           xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"  
           xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
           xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
           xmlns:navigation
="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           xmlns:sdk
="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
           xmlns:vm
="clr-namespace:Silverlight40.WCFRIAServices.DomainServiceAndMVVM"
           Title
="Demo Page" >
    
< Grid  x:Name ="LayoutRoot" >
        
< StackPanel  HorizontalAlignment ="Left" >

            
<!--
                在 View 中引入 ViewModel
            
-->
            
< StackPanel.DataContext >
                
< vm:ProductViewModel  />
            
</ StackPanel.DataContext >
            
            
<!--
                用于演示添加记录
            
-->
            
< StackPanel  Orientation ="Horizontal" >
                
< sdk:Label  Name ="lblProductName4Add"  Content ="产品名称(添加用):"   />
                
< TextBox  Name ="txtProductName4Add"  Width ="100"   />
                
< Button  Name ="btnAdd"  Content ="新增"  Command =" {Binding InsertCommand} "  CommandParameter =" {Binding ElementName=txtProductName4Add, Path=Text } "   />
            
</ StackPanel >

            
<!--
                用于演示查询记录
            
-->
            
< StackPanel  Orientation ="Horizontal" >
                
< sdk:Label  Name ="lblProductName"  Content ="产品名称(查询用):"   />
                
< TextBox  Name ="txtProductName"  Width ="100"   />
                
<!--
                    如果 Command 需要传递多个参数,则可以
                        1、将 CommandParameter 绑定到一个容器控件,然后在 Command 中去遍历容器控件内的控件(破坏 ViewModel)
                        2、在 View 中调用 Command 之前构造一个复杂类型,再传递给 ViewModel(破坏 View)
                        3、ViewModel 中设置一个对象,其是 Model 层中的某个类的实例,同时此对象双向绑定到 View 上,这样这个复杂类型就可以通过 ViewModel 来传递
                
-->
                
< Button  Name ="btnFilter"  Content ="查询"  Command =" {Binding FilterCommand} "  CommandParameter =" {Binding ElementName=txtProductName, Path=Text } "   />
            
</ StackPanel >

            
<!--
                用于演示显示记录
            
-->
            
< sdk:DataGrid  Name ="dataGrid"  Width ="600"  Height ="300"  AutoGenerateColumns ="False"  ItemsSource =" {Binding Data} " >
                
< sdk:DataGrid.Columns >
                    
< sdk:DataGridTextColumn  Header ="供应商ID"  Binding =" {Binding SupplierID} "  IsReadOnly ="True"   />
                    
< sdk:DataGridTextColumn  Header ="产品类别ID"  Binding =" {Binding CategoryID} "  IsReadOnly ="True"   />
                    
< sdk:DataGridTextColumn  Header ="产品ID"  Binding =" {Binding ProductID} "  IsReadOnly ="True"   />
                    
< sdk:DataGridTextColumn  Header ="产品名称"  Binding =" {Binding ProductName} "   />
                
</ sdk:DataGrid.Columns >
            
</ sdk:DataGrid >

            
<!--
                用于演示删除记录
            
-->
            
< Button  Name ="btnDelete"  Content ="删除选中(可多选)"  Command =" {Binding DeleteCommand} "  CommandParameter =" {Binding ElementName=dataGrid, Path=SelectedItems } "   />

            
<!--
                用于演示更新记录
            
-->
            
< Button  Name ="btnSave"  Content ="保存全部"  Command =" {Binding UpdateCommand} "   />
            
        
</ StackPanel >
    
</ Grid >
</ navigation:Page >



OK
[源码下载]

你可能感兴趣的:(silverlight)