[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 小庄 阅读(4093) 评论(76) 编辑 收藏

 回复 引用 查看   
#1楼[楼主] 2011-05-30 13:02 小庄      
源代码已更新,下载地址:http://files.cnblogs.com/xiaozhuang/SLWCFRIADemo.rar
 回复 引用 查看   
#2楼 2011-05-30 13:07 discover      
支持博主!这种架构应该是silverlight最新,或者最潮流的架构了
 回复 引用 查看   
#3楼 2011-05-30 13:58 0x0qwe      
没看到mef怎用。。。
 回复 引用 查看   
#4楼[楼主] 2011-05-30 14:39 小庄      
引用0x0qwe:没看到mef怎用。。。

MEF的应用请看代码,并注意App.cs中容器初始化部分的代码。

 回复 引用 查看   
#5楼 2011-05-31 01:57 freebirdwww      
博主!能不能给小弟发一份完整的代码!小弟是新人!还得好好学习一下!
谢谢了!我的邮箱:freebirdwww@163.com

 回复 引用 查看   
#6楼[楼主] 2011-05-31 10:25 小庄      
@freebirdwww
已经将最新源码发到你的邮箱

 回复 引用 查看   
#7楼 2011-05-31 10:33 君子以自强不息      
博主!能不能给发一份完整的代码!非常感谢
我的邮箱:wangfeng0215@126.com 

 回复 引用 查看   
#8楼[楼主] 2011-05-31 10:54 小庄      
@君子以自强不息
已经将最新源码发到你的邮箱

 回复 引用 查看   
#9楼 2011-05-31 15:20 hj.liao      
楼主,麻烦发个完整的代码,谢谢!
邮箱:hj_liao@126.com

 回复 引用 查看   
#10楼[楼主] 2011-05-31 16:53 小庄      
@hj.liao
已经将最新源码发到你的邮箱

 回复 引用 查看   
#11楼 2011-05-31 17:09 dino623      
我也想要源代码,谢谢了。
cjh623@gmail.com

LZ你好,看到你的案例觉得非常好,我是一个SL初学者,这个例子很不错,我下载了一下版本但是有错,希望LZ能给我一个完整版本好吗? 我邮箱
xiaoran619@yeah.net
非常感谢您。

 回复 引用 查看   
#13楼 2011-05-31 22:34 银光照钒粉      
能发给我一份完整的吗?506750072@qq.com谢谢
 回复 引用 查看   
#14楼 2011-06-01 00:15 ghk      
楼主,能给我也发一份吗?ghkjpm@126.com谢谢 !!!
 回复 引用 查看   
#15楼 2011-06-01 08:49 hj.liao      
引用小庄:
@hj.liao
已经将最新源码发到你的邮箱


已经收到!
非常感谢!

LZ 以下几个DLL报错,在哪有下载的呢,
Microsoft.Practices.Prism.dll
System.Windows.Controls.Tookit.dll
System.Windows.Interactivity.dll

还有 WCF RIA Services传输数据和WCF传输数据有什么区别,


 回复 引用 查看   
#17楼[楼主] 2011-06-01 12:01 小庄      
@ghk
@银光照钒粉
@好好学习,天天向上.
@dino623
已经将最新源码发到你的邮箱

 回复 引用 查看   
#18楼[楼主] 2011-06-01 12:04 小庄      
引用好好学习,天天向上.:
LZ 以下几个DLL报错,在哪有下载的呢,
Microsoft.Practices.Prism.dll
System.Windows.Controls.Tookit.dll
System.Windows.Interactivity.dll

还有 WCF RIA Services传输数据和WCF传输数据有什么区别,


这些DLL在源代码里有,也可以在网上下载到!一般的增删改查操作建议用WCF RIA Services,它能自动生成实体和增删改查操作,其实它也是基于WCF的。

哦LZ 在看你这DEMO之前我也做了个简单的 sl4.0+wcf+linq+ef 做了个简单的操作,但是我创建的是WCF服务应用程序,在SL项目里面必须得添加服务才可以访问,对WCF RIA Services 还确实 不太了解这二者的关系,有机会我也开个博克一起学习学习。SL
LZ 大人你好,Microsoft.Practices.Prism.dll 是一个框架是吗?
我去http://compositewpf.codeplex.com/上下载下来是一个
Prismv4.exe这样的文件,不能安装这是为什么下载错了吗?LZ能否提供一个链接地址,感激不尽呀。







一共就这三步然后就安装不了

谢谢楼主,我也运行成功,但是看了代码之后,有点疑问,
一共有以下几个疑问
第一:<Button FontFamily="Arial,Microsoft YaHei" Width="75" Height="23" Margin="5,0,0,0" Content="新增员工" Command="{Binding NewCommand}"/> 不太了解这个command 怎么调用

第二:既然用的是WCF,为什么项目里面没有添加服务引用,难道是RIA SERVICE的强大之处?

第三如何通过一个类就能够定位准备的页面,例如我现在有一个类更新的类,如果能够定位到add.xaml 页面, 难道和MVC差不多吗?通过名字来进行映射?

好多不懂。

 回复 引用 查看   
#24楼[楼主] 2011-06-03 15:02 小庄      
@好好学习,天天向上.
你先熟悉下文章中“示例采用技术说明”部分的相关技术吧

 回复 引用 查看   
#25楼 2011-06-05 22:38 H.I.D      
案例研究了几天,一直被一个问题困扰
我按楼主的办法使用RIA Service Class Lib
但是始终无法再客户端成功读取Ria Service的数据
我通过新建一个Test SL App来测试,提示报错服务端无响应,还有时候出现过File和http的传说中的错误。。。郁闷啊,求解,为何我用Ria Service Class Lib有问题呢?
(按照网上添加Ria Service Class Lib的方法进行的操作)

 回复 引用 查看   
#26楼[楼主] 2011-06-07 10:29 小庄      
你是否在Silverlight宿主Web项目中的Web.config文件中怎加了一些配置呢?请参考代码中的Web.config配置
支持下LZ,今天花了半天时间看了下,找到切入点了,自己尝试用现有的代码做了另外一个页面,但是还是遇到很多问题,也正在琢磨之中,LZ这个DEMO很好, 很适合新手,但是不知道目前MVVM这个框架实用用,好不好找工作,我学SL就是为了找工作而学的。
LZ呀,有个问题实在是看了好久也没能真正理解,用起来 全是错误,
例如 <sdk:DataGrid x:Name="dataGrid" AutoGenerateColumns="False"
ItemsSource="{Binding Path=AllEmployee}"

绑定这个方法是查询所有员工信息
后台的话
private Lazy<ViewModelBase> viewModelExport;
viewModelExport = App.Container.GetExport<ViewModelBase>("MainPageViewModel");
ViewModelBase vmBase = viewModelExport.Value;
this.DataContext = vmBase;

我真不太明白 viewModelExport.Value;到底是怎么去调用AllEmployee方法的,又是怎么把结果给返回的?求解答下

LZ我QQ 396464010 能加下不,你这个例子我很喜欢看了也掌握了一定的基础,但是有些疑问能否加个QQ向您讨教一下,学习学习 .
LZ帮忙看下这个方法,这个方法是通过参数查询员工信息

public void GetEmployeeAsync(EmployeeQueryEntity entity)
{
this.PerformQuery<Employee>(this.Context.GetEmployeeByQuery(entity.DepartmentID, entity.EmployeeTypeID, entity.EmployeeNO, entity.EmployeeName, entity.PageSize, entity.CurrentPage), GetEmployeeComplete);
}

其中PerformQuery()这个方法接收二个参数,第一个为 EntityQuery<T>
第二个参数为一个EventHandler事件
这里主要对第一个参数有所不理解 this.Context.GetEmployeeByQuery()这个方法里面传要查询的条件,而这个方法在哪定义的呢? 在TestDBDomainContext类里面,而这里面的是自动生成的,请问这个方法怎么自动用工具生成的,如果是手动改的话重新生成就没有了,麻烦LZ看到了帮忙解答下, 在下感激不尽呀,这个问题困扰了我一天了,求解答。

LZ帮忙看下这个方法,这个方法是通过参数查询员工信息

public void GetEmployeeAsync(EmployeeQueryEntity entity)
{
this.PerformQuery<Employee>(this.Context.GetEmployeeByQuery(entity.DepartmentID, entity.EmployeeTypeID, entity.EmployeeNO, entity.EmployeeName, entity.PageSize, entity.CurrentPage), GetEmployeeComplete);
}

其中PerformQuery()这个方法接收二个参数,第一个为 EntityQuery<T>
第二个参数为一个EventHandler事件
这里主要对第一个参数有所不理解 this.Context.GetEmployeeByQuery()这个方法里面传要查询的条件,而这个方法在哪定义的呢? 在TestDBDomainContext类里面,而这里面的是自动生成的,请问这个方法怎么自动用工具生成的,如果是手动改的话重新生成就没有了,麻烦LZ看到了帮忙解答下, 在下感激不尽呀,这个问题困扰了我一天了,求解答。

 回复 引用 查看   
#32楼[楼主] 2011-06-10 14:27 小庄      
@好好学习,天天向上.
建议你先看下MVVM和WCF RIA Service的基础知识。

 回复 引用 查看   
#33楼 2011-06-15 10:42 TH0000      
楼主您好 我想要一份源码研究谢谢您,
liyangsky-123@163.com

 回复 引用 查看   
#34楼 2011-06-15 17:57 TH0000      
楼主您好!求您一份完整的 源码看看, 谢谢您!!
Mail:liyangsky-123@163.com

 回复 引用 查看   
#35楼[楼主] 2011-06-17 10:32 小庄      
@TH0000
已经将最新代码发到你的邮箱,比这篇文章的代码部分改动。

楼主,我跟你发的消息看到了吗? 我这边有个很急的关于RIA的一个问题,很希望能够得到你的帮助。
 回复 引用 查看   
#37楼[楼主] 2011-06-20 11:22 小庄      
@好好学习,天天向上.
我没发现你给我发的消息啊?你发到哪里去了?

 回复 引用 查看   
#38楼 2011-06-21 10:26 Ray.Yan      
vicyber@126.com 忘能有一份源码学习,谢谢~
 回复 引用 查看   
#39楼[楼主] 2011-06-21 18:22 小庄      
@Ray.Yan
已经将最新代码发到你的邮箱,比这篇文章的代码有改动。

 回复 引用 查看   
#40楼 2011-06-23 08:17 andsum      
你好,我是SL的初学者,能发一份源码给我学习学习吗?谢谢!邮箱11426187897@qq.com
 回复 引用 查看   
#41楼 2011-06-23 20:03 mrqinsheng      
你好,我现在正想做这种功能,还是个初学者,能发一份源码给我吗?谢谢!!!万分感谢!!!邮箱:576995877@qq.com
 回复 引用 查看   
#42楼[楼主] 2011-06-27 15:34 小庄      
@mrqinsheng
@andsum
已经将最新代码发到你的邮箱,比这篇文章的代码有改动,加入了Prism

 回复 引用 查看   
#43楼 2011-06-27 22:14 爬树      
小庄,我最近在学这方面的内容,能给我一份最新的源码参考吗?谢谢
email: 39140281@qq.com

 回复 引用 查看   
#44楼[楼主] 2011-07-05 11:22 小庄      
@爬树
已经将最新代码发到你的邮箱.

 回复 引用 查看   
#45楼 2011-07-10 10:07 Yang.G      
楼主,能不能将最新的程序发给我一份。万分感谢。
koala_sea@163.com

 回复 引用 查看   
#46楼 2011-07-15 10:26 蒋坤      
博主你好!我是SL的初学者,能发一份源码给我学习学习吗?谢谢!邮箱kun.jiang@soliton.com.cn
 回复 引用 查看   
#47楼[楼主] 2011-07-19 16:28 小庄      
@蒋坤
@Yang.G
已经将最新代码发到你的邮箱.

 回复 引用 查看   
#48楼 2011-07-26 08:20 heyang      
博主你好!我是初学者,请发一份源码给我,谢谢!
邮箱:szhe100@163.com

 回复 引用 查看   
#49楼[楼主] 2011-07-26 16:40 小庄      
@heyang
最新的源代码在一楼!

 回复 引用 查看   
#50楼 2011-07-30 11:56 fulee207      
@小庄
我來自台灣 目前正在找此方面資料 能否寄送一份源碼給我 謝謝!

 回复 引用 查看   
#51楼 2011-07-31 10:23 lizhiqiang1191      
LZ 我估计我接下来的工作就要接触到这些 可不可以给我发个源码 研究研究学习学习 我的邮箱lizhiqiang119@126.com
 回复 引用 查看   
#52楼 2011-08-01 09:47 罗铭      
LZ威武 给我发个完整源码吧 谢谢了啊 我最近在学习这个东西 再次拜谢luozongyuan@163.com
 回复 引用 查看   
#53楼[楼主] 2011-08-01 16:33 小庄      
@罗铭
@lizhiqiang1191
@fulee207
源代码已更新到最新版,下载地址在一楼,我建议看看用Prism打造自己的程序开发架构那篇随笔,和这个结合起来才能完美。

 回复 引用 查看   
#54楼 2011-08-03 09:57 学海里的前行者      
楼主能不能给小弟也发一个源码,小弟刚接触Silverlight
邮箱地址:grjworld@163.com 谢谢

 回复 引用 查看   
#55楼[楼主] 2011-08-03 10:47 小庄      
@学海里的前行者
看楼上!

 回复 引用 查看   
#56楼 2011-09-02 11:29 大树todd      
LZ,连接的代码是最新的吗?新公司有用到这个,所以学习下,谢谢!
我的邮箱mvp@live.it

 回复 引用 查看   
#57楼 2011-09-09 13:39 FTF      
楼主你好,能不能给小弟发一个完整源码呀,谢谢了哈
邮箱:123925847@qq.com 随时刷新,坐等源码

 回复 引用 查看   
#58楼[楼主] 2011-09-16 09:44 小庄      
@FTF
@大树todd
同志们啊,源码在一楼啊!

 回复 引用 查看   
#59楼 2011-10-10 16:57 Jiangcb      
感谢楼主分享的实例,在其中学到很多东东!给份数据库吧!不胜感激!
邮箱:longit@163.com

 回复 引用 查看   
#60楼 2011-10-10 21:57 Jiangcb      
楼主啊!发个数据库吧!能跑起来但没数据!
mail:longit@163.com

 回复 引用 查看   
#61楼[楼主] 2011-10-11 11:54 小庄      
@Jiangcb
数据库备份文件就在源文件里面啊!

 回复 引用 查看   
#62楼 2011-10-12 15:23 Jiangcb      
粗心没看到。网上也有类似讲解silverlight + mvvm 的例子可都没有用到数据库(wcf来实现的)。楼主能否做个Silverlight + mvvm +wcf 的Demo 让我们学习一下!不胜感激!
 回复 引用 查看   
#63楼 2011-10-13 17:58 Evan Yao      
楼主威武
 回复 引用 查看   
#64楼[楼主] 2011-10-14 09:50 小庄      
@Evan Yao
@Jiangcb
其实涉及到数据库的操作建议还是使用RIAService来做,用WCF开发效率太低,且默认配置效率不高,RIAService也是基于WCF构造的,也可以像WCF那样自己构造操作契约和数据契约,而且比WCF方便。
这篇文章中的例子只是一个简单的实现,其中有很多不完善的地方,我建议大家把这个例子和《用Prism打造自己的程序开发架构》那个例子结合起来,才能成为一个较完整的开发框架。

 回复 引用 查看   
#65楼 2011-10-26 18:20 锋过无痕      
博主!能不能给小弟发一份完整的代码!刚学习这个!
谢谢了!我的邮箱:gzcycf@163.com
 

 回复 引用 查看   
#66楼[楼主] 2011-10-27 09:51 小庄      
@锋过无痕
最新的源码在一楼啊!

 回复 引用 查看   
#67楼 2011-11-08 12:47 逆时针の风      
楼主,最后一点关于 绑定row的那部分是不是可以这样:

SLIVERLIGH
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreparingCellForEdit">
<i:InvokeCommandAction Command="{Binding GetCommentCommand}" CommandParameter="{Binding SelectedItem, ElementName=dataGrid}"/>
    			</i:EventTrigger>
    			<i:EventTrigger EventName="RowEditEnded">
    				<i:InvokeCommandAction Command="{Binding UpdateCommentCommand}" CommandParameter="{Binding SelectedItem, ElementName=dataGrid}"/>
    			</i:EventTrigger>
    		</i:Interaction.Triggers>

 回复 引用 查看   
#68楼 2011-11-08 12:56 逆时针の风      
还有这个代理类一般是用在嵌套控件的绑定功能中,例如,dataGrid行里又嵌套一个dataGrid,那时候里面的DataGrid需要外部的context,所以用这个代理类可以解决,所以刚看你这个例子的时候没反应过来。。。
 回复 引用 查看   
#69楼 2011-11-08 13:02 逆时针の风      
抱歉没仔细看到你用了template,sorry
 回复 引用 查看   
#70楼[楼主] 2011-11-08 13:42 小庄      
@逆时针の风
感谢支持!

 回复 引用 查看   
#71楼 2011-11-08 17:33 Daniel510      
非常感谢lz提供如此好的实例,源代码已现在,但是直接跑的话出现了问题,我直接点“员工管理”的时候 ,,EmployeeMainViewModel中employeeList = null,然后就是4004代号的错误,麻烦指教下是什么问题啊,刚接触还不懂得解决啊,谢谢啦
 回复 引用 查看   
#72楼 2011-11-09 10:41 Daniel510      
问题已解决, 犯低级错误了,是数据库的链接问题 ,呵呵
 回复 引用 查看   
#73楼[楼主] 2011-11-10 10:32 小庄      
@Daniel510
昨天看见了,因太忙没及时回复你,解决了就好。我再重申一下:这个例子要和那个自定义开发框架的例子结合起来才更好!

 回复 引用 查看   
#74楼 2011-11-16 21:19 张彦鹏      
真是好人一个,写得不错。
 回复 引用 查看   
#75楼 2011-11-22 14:47 Daniel510      
呵呵,谢谢了,没有关系的,我自己也不是天天都上园子的,也挺忙的,你这个例子真是让人长见识,对我而言还是蛮有挑战的,我看了下那个Department部分还没有完善,我争取依葫芦画个瓢啊,有问题可能还请帮忙呀。
 回复 引用 查看   
#76楼 2012-02-22 10:28 Ritchie(乞戈)      
Mark,可惜的是我看都看不懂呀。