做这个示例的目的是为了给学习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,我进行了改正,具体请参照最新代码。