[Silverlight]WCF RIA Services+Mef+MVVM实现CRUD(增删改查)示例

做这个示例的目的是为了给学习Silverlight的童鞋一些参考,并希望和大家讨论相关的一些问题,让这个示例更完善。
示例功能说明:实现了雇员的增删改查,雇员表(Employee)和部门表(Department)、雇员类型表(EmployeeType)有外键关联,并和字典表(DataDict)有字典关系

示例参考说明:主要参考了Codeproject上的http://www.codeproject.com/KB/silverlight/IssueVisionForSilverlight.aspx中的相关文章和代码。
示例采用技术说明:
1、采用了WCF RIA Services来和服务器端传输数据,具体来说就是Silverlight项目类型中的WCF RIA Services 类库项目,因为这个更快捷。
2、采用了MVVM设计模式来实现UI元素也UI界面逻辑分离,这个的好处地球人都知道。
3、采用了MEF来对Model和ViewModel、ViewModel和View之间的相互依赖进行解耦。
4、采用了Prism中的部分工具,例如采用CompositePresentationEvent来实现View和ViewModel,ViewModel和ViewModel之间的事件传递,采用NotificationObject作为ViewModel的基类,采用Prism自带的DelegateCommand。
示例项目结构说明:

1、RIAServicesLibrary 解决方案文件夹中是WCF RIA Services的两个项目,服务器端项目RIAServicesLibrary.Web为客户端提供DomainService,来实现实体的增删改查,客户

端项目RIAServicesLibrary通过RiA数据服务链接调用RIAServicesLibrary.Web,实现MVVM中的Models层,并对服务端传递过来的实体进行扩展。
2、SLWCFRIADemo主项目提供员工增删改查操作的所有相关View和ViewModel。
3、SLWCFRIADemo.Common项目顾名思义是公共层,被RIAServicesLibrary和SLWCFRIADemo引用。

在做这个Demo的过程中遇到的一些问题和解决办法:
1、怎样在Datagrid的行上触发ViewModel中的Command?
因Datagrid的ItemsSource指向ViewModel员工集合的属性,而编辑和删除Command是定义在ViewModel中的,所以在Datagrid中直接绑定编辑和删除Command是不起作用的,经查询

Google得出如下解决办法:
首先定义一个类DataContextProxy,故名思意是DataContext的代理类,代码如下:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace SLWCFRIADemo.Controls
{
public class DataContextProxy : FrameworkElement
{
public DataContextProxy()
{
this.Loaded += new RoutedEventHandler(DataContextProxy_Loaded);
}

void DataContextProxy_Loaded(object sender, RoutedEventArgs e)
{
Binding binding
= new Binding();
if (!String.IsNullOrEmpty(BindingPropertyName))
{
binding.Path
= new PropertyPath(BindingPropertyName);
}
binding.Source
= this.DataContext;
binding.Mode
= BindingMode;
this.SetBinding(DataContextProxy.DataSourceProperty, binding);
}

public Object DataSource
{
get { return (Object)GetValue(DataSourceProperty); }
set { SetValue(DataSourceProperty, value); }
}

public static readonly DependencyProperty DataSourceProperty =
DependencyProperty.Register(
"DataSource", typeof(Object), typeof(DataContextProxy), null);


public string BindingPropertyName { get; set; }

public BindingMode BindingMode { get; set; }

}

}


再在页面中引用这个代理类

  xmlns:my="clr-namespace:SLWCFRIADemo.Controls"

并修改相关代码如下:

 <sdk:DataGridTemplateColumn Header="修改 \ 删除" Width="100">
                                                    
<sdk:DataGridTemplateColumn.CellTemplate>
                                                        
<DataTemplate>
                                                            
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
                                                                
<HyperlinkButton Margin="5"  Content="修改" Command="{Binding Source={StaticResource DataContextProxy},Path=DataSource.ModifyCommand}"/>
                                                                
<HyperlinkButton Margin="5" Content="删除" Command="{Binding Source={StaticResource DataContextProxy},Path=DataSource.DeleteCommand}"/>
                                                            
</StackPanel>
                                                        
</DataTemplate>
                                                    
</sdk:DataGridTemplateColumn.CellTemplate>
                                                
</sdk:DataGridTemplateColumn>

搞定!
2、采用WCF RIA Services怎么处理字典表的问题。
因雇员表和字典表无外键关系,要在DataGrid中显示雇员的性别,不能直接绑定字典表实体,需要在雇员实体中做如下扩展(该扩展在RIAServicesLibrary项目):

  private EntityRef<DataDict> employeeSexDict;
         [Association(
"EmployeeSex_DataDict""EmployeeSex""DictValue", IsForeignKey = false)]
        
public DataDict EmployeeSexDict
        {
            
get
            {
                
if ((this.employeeSexDict == null))
                {
                    
this.employeeSexDict = new EntityRef<DataDict>(this"EmployeeSexDict"this.FilterEmployeeSexDict);
                }
                
return this.employeeSexDict.Entity;
            }
            
set
            {
                DataDict previous 
= this.EmployeeSexDict;
                
if ((previous != value))
                {
                    
this.ValidateProperty("EmployeeSexDict", value);
                    
if ((previous != null))
                    {
                        
this.employeeSexDict.Entity = null;
                    }
                    
if ((value != null))
                    {
                        
this.EmployeeSex = value.DictValue;
                    }
                    
else
                    {
                        
this.EmployeeSex = default(int);
                    }
                    
this.employeeSexDict.Entity = value;
                    
this.RaisePropertyChanged("EmployeeSexDict");
                }
            }
        }
        
private bool FilterEmployeeSexDict(DataDict entity)
        {
            
if (this.EmployeeSex.HasValue)
                
return (entity.DictValue == this.EmployeeSex.Value);
            
else
                
return false;
        }

 

这样就可以直接绑定字典表实体了。
大家对这个示例有什么问题或意见?

更新(2011-05-31):根据Mainz的这篇http://www.cnblogs.com/Mainz/archive/2011/05/27/2059940.html,对代码进行了修改,将查找和分页放在了服务器端,Mainz的代码有点小Bug,我进行了改正,具体请参照最新代码。

 

posted @ 2011-05-30 12:51  小庄  阅读(...)  评论(...编辑  收藏