转自 http://amar-yao.cnblogs.com/
这部分应该是目前XCenter中的最吸引人的地方。首先要感谢chegan的贡献。这里我算站在巨人的肩膀上了,
先看一下效果图:
开始阶段其实我根本没有想用什么流程设计器来实现。只是随着逐渐贴近核心业务逻辑,感觉作为编辑器和设计器,过于复杂的操作界面会使开发人员和用户都感觉 到无所适从甚至抓狂。本着简化UI的目的我简单看了一下chegan的Silverlight流程设计器。这个设计器本身是个很通用的工具,可以用来实现 XCenter中的查询模型设计器和格式模型设计器。而且其中的用XML序列化布局的逻辑很XCenter的核心存储逻辑很相似(XCenter把查询模 型实例序列化为XML存储在数据库中的Blog字段)。
由于流程设计器本身比较独立,我将核心代码放置到XCenter.Framework.Client的SmartEditor目录。目录结构和 chegan的目录结构一致,只是修改了命名空间。由于chegan的流程设计器主要面对工作流,各个节点的图示都是根据代码画出来的。XCenter中 的各个节点无需根据逻辑呈现不同内容,先对固定,所以用固定的图标显示节点更为美观实用。这就免不了要修改chegan的流程设计器。
以下我只列出我的修改,关于chegan流程设计器的详细知识请见其Blog http://www.cnblogs.com/chegan/archive/2009/04/22/1440872.html 。如果chegan有幸看到这边文章请指正我修改得不妥的地方。
首先我要实现节点图标的现实就必须新建一种ActivityType,这里要修改IElement.cs中的ActivityType并添加一种自定义的类型,IMAGE_48X。
由于Activity.xaml.cs中要根据ActivityType的不同进行不同情况的处理,例如位置、显示等。我们要修改所有涉及到ActivityType分支的部分,相应的添加对我们的自定义类型IMAGE_48X的支持。
修改位置为:GetPointOfIntersection方法,RepeatDirection的Set访问器,Activity的构造器,Type的 Set访问器。具体我就不说了,大家可以先了解chegan的流程设计器原理再根据代码一步步修改以实现自己的需求。
最后由于chegan的流程设计器的Container部分逻辑比较复杂,而XCenter中的查询模型、格式模型设计部分目前没有那么复杂的逻辑,所以 我基于chegan的Container实现自己重新写了适合XCenter的设计器容器,它位于XCenter.QueryEngine.Client 项目的Designer目录。
这样一来流程设计器好像是一个多功能的插座,我们现在只需把各个节点的编辑界面挂在不同类型的节点上就可以了,大大简化了交互界面。
![](https://i-blog.csdnimg.cn/blog_migrate/8f3d8bd6e760ad0a5ec47e638b44bc1a.gif)
先看一下效果图:
![](https://i-blog.csdnimg.cn/blog_migrate/b728fb68719df6e8809015dc5ee1f795.jpeg)
开始阶段其实我根本没有想用什么流程设计器来实现。只是随着逐渐贴近核心业务逻辑,感觉作为编辑器和设计器,过于复杂的操作界面会使开发人员和用户都感觉 到无所适从甚至抓狂。本着简化UI的目的我简单看了一下chegan的Silverlight流程设计器。这个设计器本身是个很通用的工具,可以用来实现 XCenter中的查询模型设计器和格式模型设计器。而且其中的用XML序列化布局的逻辑很XCenter的核心存储逻辑很相似(XCenter把查询模 型实例序列化为XML存储在数据库中的Blog字段)。
由于流程设计器本身比较独立,我将核心代码放置到XCenter.Framework.Client的SmartEditor目录。目录结构和 chegan的目录结构一致,只是修改了命名空间。由于chegan的流程设计器主要面对工作流,各个节点的图示都是根据代码画出来的。XCenter中 的各个节点无需根据逻辑呈现不同内容,先对固定,所以用固定的图标显示节点更为美观实用。这就免不了要修改chegan的流程设计器。
以下我只列出我的修改,关于chegan流程设计器的详细知识请见其Blog http://www.cnblogs.com/chegan/archive/2009/04/22/1440872.html 。如果chegan有幸看到这边文章请指正我修改得不妥的地方。
首先我要实现节点图标的现实就必须新建一种ActivityType,这里要修改IElement.cs中的ActivityType并添加一种自定义的类型,IMAGE_48X。
由于Activity.xaml.cs中要根据ActivityType的不同进行不同情况的处理,例如位置、显示等。我们要修改所有涉及到ActivityType分支的部分,相应的添加对我们的自定义类型IMAGE_48X的支持。
修改位置为:GetPointOfIntersection方法,RepeatDirection的Set访问器,Activity的构造器,Type的 Set访问器。具体我就不说了,大家可以先了解chegan的流程设计器原理再根据代码一步步修改以实现自己的需求。
最后由于chegan的流程设计器的Container部分逻辑比较复杂,而XCenter中的查询模型、格式模型设计部分目前没有那么复杂的逻辑,所以 我基于chegan的Container实现自己重新写了适合XCenter的设计器容器,它位于XCenter.QueryEngine.Client 项目的Designer目录。
这样一来流程设计器好像是一个多功能的插座,我们现在只需把各个节点的编辑界面挂在不同类型的节点上就可以了,大大简化了交互界面。
![](https://i-blog.csdnimg.cn/blog_migrate/04b944c2f8db80472b20127913c4f5be.jpeg)
目前实体类是我们采用的Silverlight与WCF传递数据的首选方法。但这种方法相对比较死,只能适用于业务逻辑比较简单的应用程序。对于那些在运 行时才能知道具体数据的应用并不适合。相比之下传统的Aod.Net DataSet,DataTable具有很大的灵活性。但无奈在Silverlight端不被支持。
网上已经有很多种通过特殊处理来变相实现Silverlight传递DataTable(DataSet)的文章。其中最典型的就是利用.Net Framework3.5的动态编译技术。前面查询建模系列中已经有所应用。但这种实现方法存在着严重的弊端就是动态编译过程相对较慢如果不进行缓存处理 将极大的影响应用的性能。即使做了缓存处理当数据传递比较频繁时也会有性能降低的危险。而且就我在XCenter中的实现还存在着传递数据量的问题,由于 XCenter中的DataSetData中的数据以List<List<object>>存储,数据在传递之前没有进行压缩处 理。所以注定知能适合少量数据的传递。
最近在网上看到一个加拿大的网站公开了一个类库。很好的解决Silverlight传递DataTable的难题。大概的思路就是在 Silverlight端实现了一套类似Ado.Net DataSet,DataTable的API并且通过Xml传递数据。更可贵的是自动提供了对Xml的压缩功能(他的压缩实现基于对所传递的xml数据的 简化)。如果这种压缩还不能达到我们对大数据量传递的要求。我们可以应用第三方Silverlight压缩组件进一步进行压缩并传递。这样的类库在 CodePlex上很多。
官方网站 http://silverlightdataset.net/silverlightdataset/Default.aspx
有喜爱并了解的朋友可以和我交流。
网上已经有很多种通过特殊处理来变相实现Silverlight传递DataTable(DataSet)的文章。其中最典型的就是利用.Net Framework3.5的动态编译技术。前面查询建模系列中已经有所应用。但这种实现方法存在着严重的弊端就是动态编译过程相对较慢如果不进行缓存处理 将极大的影响应用的性能。即使做了缓存处理当数据传递比较频繁时也会有性能降低的危险。而且就我在XCenter中的实现还存在着传递数据量的问题,由于 XCenter中的DataSetData中的数据以List<List<object>>存储,数据在传递之前没有进行压缩处 理。所以注定知能适合少量数据的传递。
最近在网上看到一个加拿大的网站公开了一个类库。很好的解决Silverlight传递DataTable的难题。大概的思路就是在 Silverlight端实现了一套类似Ado.Net DataSet,DataTable的API并且通过Xml传递数据。更可贵的是自动提供了对Xml的压缩功能(他的压缩实现基于对所传递的xml数据的 简化)。如果这种压缩还不能达到我们对大数据量传递的要求。我们可以应用第三方Silverlight压缩组件进一步进行压缩并传递。这样的类库在 CodePlex上很多。
官方网站 http://silverlightdataset.net/silverlightdataset/Default.aspx
有喜爱并了解的朋友可以和我交流。
摘要: 这个系列的话题似乎越来越简单了。不过没关系我们怎么简单怎么来,生活就应该是这样。 说到页面布局在asp.net中我们已经尝试过很多种了。但最经典的还是类似左树右表的结构。今天我们就来说说XCenter主页面的结构。先看下面的截 图, 工具栏在前几节已经说过了。下面说左树右表结构,这个结构得益于EasySL的UI框架这里再次谢过。XCenter项目中 XCenter.UI.Page就是这个主界面的实现。...
阅读全文
我们都知道Silverlight端不能直接使用DataTable,DataSet等数据存储。但某些情况下实体类的传递方式根本无法满足我们的需求。 举个例子,在进行查询建模时我们根本不知道用户从哪张表选择字段,更有甚者我们还可能不知道用户从哪个数据源选择表(这个问题我通过SmartDAL的特 性加以支持)。这种情况下我们无法建立实体类定义。这也是我使用C#,Java这些静态语言感觉最不爽的地方。动态语言中这种处理相当简单。
我在XCenter中的实现思想就是Server端(WCF实现端)将SmartDAL取出的DataTable分为数据和元数据两部分存储并通过WCF 端进行传递。在Silverlight端根据元数据信息动态生成并编译出动态实体类实例。并填充真实的待绑定集合。由于在Silverlight端动态生 成并编译实体类的过程比较耗时所以在Silverlight端建立了缓存。并用元数据中的唯一Id进行标识。
元数据定义在XCenter.Framework.Public.DataSetData命名空间。主要结构就是3个类。
Field.cs 字段信息(部分定义)
Code
MetaData.cs 元数据定义
Code
DataSetData.cs 数据集定义
Code
Field对应于DataTable中的列信息。MetaData主要就是对Field进行封装,并实现一些公共的操作方法。DataSetData封装了MetaData并用List<List<object>>存放具体数据。
这里要说明一下,由于从DataTable取出的实际数据都是基本类型(int,string,byte[]...)等WCF中可以直接传递的数据。所以 这里用List<List<object>>传递数据不会有问题。如果List中有用户定义类型,不在 ServiceKnownType中事先声明,那么Silverlight端反序列化时会报错。
以IQEObjectStorage这个WCF服务接口的GetData方法可以看出具体的WCF声明:
这里的DSDReturnDataVO只是XCenter中为所有能返回DataSetData的服务定义的统一的返回值。读者可以直接返回 DataSetData。这个服务其实就是手工Sql设计的取数方法。其内部处理逻辑是将查询模型解析成Sql送到数据库执行并取得DataTable组 装DataSetData。这里的具体逻辑我们暂时不关心。
下面看看SL端对传来的DataSetData的处理过程。我们可以看QueryMain.xaml.cs的service_GetDataCompleted方法,这个方法最初是由工具栏中的运行查询按钮触发。
Code
可以看到主要的处理逻辑被封装在DataSetData的扩展方法:ToDataSource()中,这里代码就不贴了,读者可以结合本贴看看里面的具体 实现步骤。主要就是先在缓存中根据MetaData的唯一标识查找动态生成的类实例,如果没有找到那么就启动动态编译并把生成的实例加入缓存以备下次再 用。要说一下的是这个缓存其实就是定义在App中的字典字段:
Code
只不过通过WindowHelper进行了引用。WindowHelper.TempClassDic。
最后要提醒读者,到这里这个解决方案并不完美,因为我们没有考虑数据量的问题。当数据量很大时WCF传递数据会有问题。我们可以将DataSetData 中的List<List<object>>数据的形式改为Byte[]并进行压缩再传递(或者是JSON),这样的话SL端又多 了一道加压缩的过程。但个人认为这并不是最完善的解决方法。最终突破数据量的问题可能最好的还是分块传递。可能用到WCF双向通讯的技术。这方面有经验的 朋友可以分享一下经验。
我在XCenter中的实现思想就是Server端(WCF实现端)将SmartDAL取出的DataTable分为数据和元数据两部分存储并通过WCF 端进行传递。在Silverlight端根据元数据信息动态生成并编译出动态实体类实例。并填充真实的待绑定集合。由于在Silverlight端动态生 成并编译实体类的过程比较耗时所以在Silverlight端建立了缓存。并用元数据中的唯一Id进行标识。
元数据定义在XCenter.Framework.Public.DataSetData命名空间。主要结构就是3个类。
Field.cs 字段信息(部分定义)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
DataSetData.cs 数据集定义
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
Field对应于DataTable中的列信息。MetaData主要就是对Field进行封装,并实现一些公共的操作方法。DataSetData封装了MetaData并用List<List<object>>存放具体数据。
这里要说明一下,由于从DataTable取出的实际数据都是基本类型(int,string,byte[]...)等WCF中可以直接传递的数据。所以 这里用List<List<object>>传递数据不会有问题。如果List中有用户定义类型,不在 ServiceKnownType中事先声明,那么Silverlight端反序列化时会报错。
以IQEObjectStorage这个WCF服务接口的GetData方法可以看出具体的WCF声明:
[OperationContract]
DSDReturnDataVO GetData(QueryBaseVO qbd, ServiceContext context);
DSDReturnDataVO GetData(QueryBaseVO qbd, ServiceContext context);
这里的DSDReturnDataVO只是XCenter中为所有能返回DataSetData的服务定义的统一的返回值。读者可以直接返回 DataSetData。这个服务其实就是手工Sql设计的取数方法。其内部处理逻辑是将查询模型解析成Sql送到数据库执行并取得DataTable组 装DataSetData。这里的具体逻辑我们暂时不关心。
下面看看SL端对传来的DataSetData的处理过程。我们可以看QueryMain.xaml.cs的service_GetDataCompleted方法,这个方法最初是由工具栏中的运行查询按钮触发。
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
可以看到主要的处理逻辑被封装在DataSetData的扩展方法:ToDataSource()中,这里代码就不贴了,读者可以结合本贴看看里面的具体 实现步骤。主要就是先在缓存中根据MetaData的唯一标识查找动态生成的类实例,如果没有找到那么就启动动态编译并把生成的实例加入缓存以备下次再 用。要说一下的是这个缓存其实就是定义在App中的字典字段:
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
只不过通过WindowHelper进行了引用。WindowHelper.TempClassDic。
最后要提醒读者,到这里这个解决方案并不完美,因为我们没有考虑数据量的问题。当数据量很大时WCF传递数据会有问题。我们可以将DataSetData 中的List<List<object>>数据的形式改为Byte[]并进行压缩再传递(或者是JSON),这样的话SL端又多 了一道加压缩的过程。但个人认为这并不是最完善的解决方法。最终突破数据量的问题可能最好的还是分块传递。可能用到WCF双向通讯的技术。这方面有经验的 朋友可以分享一下经验。
源代码下载
Silverlight实现查询建模(编外) 源代码及运行方法
Silverlight实现查询建模(一) 总揽
Silverlight实现查询建模(二) 项目层次划分
Silverlight实现查询建模(三) XAP包的动态下载
Silverlight实现查询建模(四) 更新XAP包
Silverlight实现查询建模(五) 用户登录
Silverlight实现查询建模(六) 带动画场景跳转
Silverlight实现查询建模(七) 工具栏的实现与加载
Silverlight实现查询建模(八) 传递DataTable解决方案
Silverlight实现查询建模(九) 主页面布局