[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.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; }
}
}
再在页面中引用这个代理类
并修改相关代码如下:
<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项目):
[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,我进行了改正,具体请参照最新代码。