wf框架编程(设计器部分)
五、工作流设计器
1 Net设计器基础框架
.net设计器基础框架所在的命名空间是System.ComponentModel.Design,而wf、asp.net、win from这三种设计器架构都是建立在.Net本身提供的基础框架之上。
wf设计器框架所在的命名空间是System.Workflow.ComponentModel.Design,相关类都在这个NameSpace里面。在研究wf设计器之前,我们先看看Winform设计器。对Winform设计器的研究,对WF设计器的理解很有帮助。
1.1 Winform设计器设计:
曾经研究过几天SharpDevelop,一个免费开源的IDE开发环境,并且有类似eclipse的插件思想。在这个开源IDE里面有比较完整的Winform设计器实现。Winform
IDE主要依靠下面几个接口和类实现。只要实现了相关的接口和抽象,.Net框架会帮助我们实现Winform设计器。很像模板方法。相应的接口和类为:
Winform设计器结构
ü DesingerHost:
1.服务管理:服务容器和服务提供者
2.组件管理和事务管理
ü ISite:
绑定组件和容器,DesignerHost中所有的服务都可以通过ISite(GetService)得到
ü IServiceProvide
ü IDesinger
提供定制服务,设计期在组件的上下文菜单中添加菜单命令,添加的组件实现操作
Initialize方法中与ICompont关联
工具箱实现:
ü IToolboxService
工具箱服务,主要目的是存储ToolboxItem
如何填充工具箱?
要使用ToolboxItemFilterAttribute
AddToolboxEntries:listbox.Items.Add(new SelfHostToolboxItem(entry)
CategoryNames:工具箱类别属性
AddCreator:
其中的WorkflowDesignerControl我觉得是Mediator模式的应用
ü 选取服务
相关assemblies和CCU的容器:TypeProvider
大家可以down下SharpDevelop的源代码看看,有本书专门介绍这个的。
2 WF设计器
WF设计器的实现思路主要是每个Activity对应的ActivityDesigner和驻留环境(Designer Surface),这也为我们实现基于Web的WF设计器提供了思路,就winform环境和webform环境比较,AcitivityDesinger是不变的,变化的是驻留环境。很长时间没有接触WF了,这里讨论的环境是Winfrom下的,以后有机会做的Web环境下再整理吧。
Wf设计器结构
2.1 Activity Designer
Activity关于默认的DesignerAttribute声明是Designer(typeof(ActivityDesigner), typeof(IDesigner);Designer(typeof(ActivityDesigner), typeof(IRootDesigner)
我们如果实现自定义的Acitivity,一般从Activity继承就可以了,不需要重新写。由于ActivityDesigner的设计表现为简单矩形,所以我们看到的活动都是简单矩形的样子,当然我们也可以修改的很漂亮。对应复合活动,如图,从CompositeActivityDesigner上继承下来Desinger有好几个,都有自己的设计表现,其中:ParallelActivityDesigner表现为所有子活动并行;SequenceDesigner表现是自动以顺序方式呈现子活动。
如果是特殊的复合活动,可能需要自己实现Desinger。这里觉的例子是wf本质论上的,大家也可以比较书看一下,电子书是可以免费下载的。例子中要实现自定义的PrioritizedInterleave,设计表现是需要在设计器上表现出优先级关系,由于现有类库缺乏支持,所以就需要自己实现特点的Acitivity Designer.
如何实现自定义ActivityDesigner
PrioritizedInterleaveDesigner例子中,设计意图是点自活动可以在PropertyGrid中设置Priority属性,根据Priority值,子活动位于不特点位置
可以通过PropertyGrid设置属性
1.IExtenderListService中加入特定IExtenderProvider。见类图。
2.特定IExtenderProvider实现
通过ProvidePropertyAttribute和PropertyGrid关联
IExtenderProvider.CanExtend作为是否使用属性的依据,如果为true,PropertyGrid控件会查找extender类中的Get<PropertyName>,Set<PropertyName>方法,实现和Acivity属性的交互。
Wf还没有开源,猜测这里这里使用AOP代码织入并使用了Template模式。
3.Activity的声明使用自定义的ActivityDesigner。Designer(typeof(自定义ActivityDesigner), typeof(IDesigner)
例子中PrioritizedInterleaveDesigner继承自CompositeActivityDesigne,所以对PrioritizedInterleave的声明,实际上对整个复合活动的声明
CompositeActivityDesigner.ContainedDesigners
右键菜单修改属性
1.实现IDesignerVerbProvider接口
2.初始化活动的时候IDesignerVerbProviderService.AddVerbProvider(IDesignerVerbProvider);
3.接口实现
通过ActivityDesignerVerb.Properties得到Activity
针对这个Activity get并修改后Set
4.PerformLayout使修改生效
修改设计器图形(复合活动和基础活动都可以修改)
1.对于复合活动override Glyphs方法,得到ActivityDesignerGlyphCollection
ActivityDesignerGlyphCollection.Add(DesignerGlyph);
2.DesignerGlyph的实现
override方式实现DesignerGlyph的GetBounds和OnPaint方法
3.对于简单活动,直接override实现ActivityDesigner的OnLayoutSize,OnPaint方法
OnLayoutSize:返回大小
OnPaint:实现了一些必要的绘图功能
GetBounds:返回代表图形边界的矩形
修改设计器布局
重载Acitivity Designer的OnLayoutSize和OnLayoutPosition
OnLayoutSize返回设计器的合计大小尺寸,OnLayoutPosition计算出子活动的偏移。
设计器主题
1.实现特定的ActivityDesignerTheme
2.再通过ActivityDesignerThemeAttribute注入
3.ActivityDesigner.OnPaint中可以调用Theme
工具箱
默认是通过ToolboxItemAttribute指向ActivityToolboxItem。
如果有特殊需求,例如在托拽的时候要实现复合控件可以继承ActivityToolboxItem,并在CreateComponentsCore中实现
这时候ToolboxItemAttribute指向自定义的ActivityToolboxItem
使用ToolboxBitmapAttribute可以在工具箱实现自定义视图
2.2 驻留设计器
Designer Surface:职责是管理Designer Host,管理与用户交互(得到view,得到host,异步加载Designer加载器)
Designer Host的职责
1.管理IComponent和相关的IDesigner之间的交互;
2.是一个服务容器,提供取消、剪切板功能和其它活动设计器需要的功能。
事务管理
组件管理:CreateComponent,GetDesigner,GetType
设计器的加载和管理
// 摘要:
// 在激活此设计器时发生。
event EventHandler Activated;
//
// 摘要:
// 在停用此设计器时发生。
event EventHandler Deactivated;
//
// 摘要:
// 在此设计器加载完文档时发生。
event EventHandler LoadComplete;
Designer View的职责
1.呈现各种ActivityDesigner,向各个ActivityDesigner发送消息
2.窗体管理、命令路由、窗体滚动、托放、滚动、布局、打印和打印预览
ISite的职责是绑定组件和容器,DesignerHost中所有的服务都可以通过ISite(GetService)得到
IServiceContainer是服务容器,可以形成树,promote参数true,服务的添加和删除操作会提交给基容器,这些接口的实现思路和winfrom的设计器实现思路非常像。
2 设计器序列化
像VS一样,流程设计出来必须要持久化保存,下次使用或者修改的时候通过反序列化操作,我们可以得到曾经设计的流程。
我们可以将活动树序列化为XAML或者代码(默认),甚至可以序列化为(BPEL,DSL)等领域描述语言。序列化为什么格式,可以在Acitivity的Attribute中指定。
TypeCodeDomSerializer:序列化为代码
WorkflowMarkupSerializer:序列化为XAML文件
设计器序列化使用的类库
4 代码生成
如果流程中存在Code Activity,那么还需要设计器能动态生成代码。如果指定了TypeCodeDomSerializer,也需要动态代码生成,最后整个WF活动才能通过编译成为.Net下的Assembly
活动代码生成在验证后调用C#代码编译前执行,活动代码生成实际上是给了一个使用CodeDOM生成代码文件的机会。代码生成下次说吧。