制作自定义工作流(WWF)设计器

本文介绍了如何在程序中使用Windows Workflow Foundation (WWF)的自定义设计器,并提供了设计器类和功能实现的具体方法。文中详细解释了如何创建自定义视图、如何加载和显示工作流,以及如何通过自定义服务扩展设计器的功能。

注:

l         这是一篇翻译,来自http://msdn2.microsoft.com/en-us/library/aa480213.aspx

l         对于一些细节我没有完全翻译

l         增加了一些我的注释,在“[]”里面

l         主要是给朋友们介绍一下这方面的情况

Vihang Dalal
Software Development Engineer Test
Microsoft Corporation<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

May 2006

应用于:
   Windows Workflow Foundation beta 2.2
   Microsoft Visual C# Version 2.0
   Visual Studio 2005

demo下载:Download the code sample, WorkflowDesignerControl.exe.

 

 

摘要:如果你在vs2005里面安装了Visual Studio 2005 extensions for Windows Workflow Foundation,你就可以使用WWF的可视化编辑器了。这篇文章就是介绍如何在自己的程序中使用这个设计器的一些方法。并且附带有一个简单的例子程序[注:确实可以使用,默认顺序工作流,可以在程序中修改实现。]

 

主要内容包括

l         自定义设计器的介绍

l         自定义设计器的类

l         主要功能和自定义的服务(Services)

l         结论

l         更多资源

 

自定义设计器的介绍:

这篇文章主要讲述了如何使用设计器的api,以及其他扩展。

我们为什么会用到自定义设计器?

l         自定义自己的视图,可以增加/减少一些实现

l         在现有的程序中加入自己的设计器

l         [我用的Web Developer 2005 Express,所以我无法安装WWF设计器,只能用这个了]

什么时候用到这个设计器?

l         设计时:可以创建、编辑工作流

l         运行时:可以跟踪工作流状态

这里提供的例子程序可以独立于vs2005开发工具之外单独运行

 

自定义设计器的类

主要包括:DesignSurface, WorkflowView, and WorkflowDesignerLoader

DesignSurface使用WorkflowDesignerLoader来创建活动(Activety)树和其他组建的树;WorkflowView则用来显示工作流实例(一个xml文件)的默认视图.

 

DesignSurface提供一个环境(self-contained)来显示设计器组件

WorkflowDesignerLoader可以用来加载(PerformLoad())和卸载(PerformFlush())一个工作流的定义。开发者可以使用者个类来自定义工作流保存的方式,可以序列化到自己的媒介中(数据库

WorkflowView是用来显示一个具体的工作流实例的。他借助DesignSurface来显示其中activety的信息。同时他也提供很多用于显示时的控制事件(OnLayout() and OnPaint()),还提供诸如SaveWorkflowAsImage()之类的函数。

 

下边这段代码可以用来制作一个简单的winform的设计器

创建自定义WorkflowDesignerLoader:(重写PerformLoad() and PerformFlush()

None.gif ·                            internal   sealed   class  WorkflowLoader : WorkflowDesignerLoader
ExpandedBlockStart.gifContractedBlock.gif·                           
dot.gif {
InBlock.gif·                              
protected override void PerformLoad(IDesignerSerializationManager serializationManager)
ExpandedSubBlockStart.gifContractedSubBlock.gif·                                 
dot.gif{
InBlock.gif·                                    
base.PerformLoad(serializationManager);
InBlock.gif·                                    
// Implement the logic to read from the serialized state,
InBlock.gif
·                                    // create the activity tree and the corresponding designer
InBlock.gif
·                                    // tree and add it to the designer host
ExpandedSubBlockEnd.gif
·                                 }

InBlock.gif·                            
InBlock.gif·                              
protected override void PerformFlush(IDesignerSerializationManager manager)
ExpandedSubBlockStart.gifContractedSubBlock.gif·                                 
dot.gif{
InBlock.gif·                                    
// Implement the logic to save the activity tree to a
InBlock.gif
·                                    // serialized state along with any code beside elements 
ExpandedSubBlockEnd.gif
·                                 }

ExpandedBlockEnd.gif·                           }

None.gif



加载工作流,显示

None.gif ·                            //  Create new Design surface and loader (created as shown above)
None.gif
·                            
None.gif·                           DesignSurface designSurface 
=   new  DesignSurface();
None.gif·                           WorkflowLoader loader 
=   new  WorkflowLoader();
None.gif·                            
None.gif·                           
//  load the design surface using the loader. This will call the
None.gif
·                            //  PerformLoad method on the loader, create the activity tree and
None.gif
·                            //  add the corresponding designer components to the designer host
None.gif
·                            
None.gif·                           designSurface.BeginLoad(loader);
None.gif·                            
None.gif·                           
//  Get the designer host and retrieve the corresponding root component
None.gif
·                           IDesignerHost designerHost  =  designSurface.GetService( typeof (IDesignerHost))  as  IDesignerHost;
None.gif·                           
if  (designerHost  !=   null   &&  designerHost.RootComponent  !=   null )
ExpandedBlockStart.gifContractedBlock.gif·                           
dot.gif {
InBlock.gif·                              
// Get the designer associated with the root component
InBlock.gif
·                              IRootDesigner rootDesigner =    designerHost.GetDesigner(designerHost.RootComponent) as IRootDesigner;
InBlock.gif·                              
if (rootDesigner != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif·                              
dot.gif{
InBlock.gif·                                 
this.designSurface = designSurface;
InBlock.gif·                                 
this.loader = loader;
InBlock.gif·                              
InBlock.gif·                                    
// Assign the default view of the rootdesigner to WorkflowView
InBlock.gif
·                                    this.workflowView = rootDesigner.GetView(ViewTechnology.Default) as          WorkflowView;
InBlock.gif·                            
InBlock.gif·                                    
// Add the workflow view control to winforms app
InBlock.gif
·                                    this.workflowViewSplitter.Panel1.Controls.Add(this.workflowView);
InBlock.gif·                                    
this.workflowView.Focus();
InBlock.gif·                                    
this.propertyGrid.Site = designerHost.RootComponent.Site;
ExpandedSubBlockEnd.gif·                              }

ExpandedBlockEnd.gif·                            }

None.gif

 

还需要一个DesignerHost类,用来装载各种服务,和向外提供各类服务接口。

https://i-blog.csdnimg.cn/blog_migrate/0052c380a0c2cdaaf01d2e38d4e82409.png

 

主要功能和自定义的服务(Services)

System.Workflow.ComponentModel提供了一些默认类的实现,比方说“IIdentifierCreationService, IReferenceService, IworkflowCompilerOptionsService”等。但是如果要自定义设计器,可能需要你客户化自己的实现类(Service

1:上下文菜单和通用设计器的功能(Context Menu And Common Designer Features:);

   菜单WorkflowMenuCommandService继承自MenuCommandService,用来显示菜单命令。这些代码用来增加一些额外的命令菜单

None.gif ·                //  Create a new context menu
None.gif
·               ContextMenu contextMenu  =   new  ContextMenu();
None.gif·               Dictionary
< CommandID,  string >  selectionCommands  =   new  Dictionary < CommandID,  string > ();
None.gif·                
None.gif·               
//  Add the required commands
None.gif
·               selectionCommands.Add(WorkflowMenuCommands.Cut,  " Cut " );
None.gif·               selectionCommands.Add(WorkflowMenuCommands.Copy, 
" Copy " );
None.gif·               selectionCommands.Add(WorkflowMenuCommands.Paste, 
" Paste " );
None.gif·               selectionCommands.Add(WorkflowMenuCommands.Delete, 
" Delete " );
None.gif·               
foreach  (CommandID id  in  selectionCommands.Keys)
ExpandedBlockStart.gifContractedBlock.gif·               
dot.gif {
InBlock.gif·                     MenuCommand command 
= FindCommand(id);
InBlock.gif·                     
if (command != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif·                      
dot.gif{
InBlock.gif·                        
// For each command create a new menu item and add an
InBlock.gif
·                        MenuItem menuItem = new MenuItem(selectionCommands[id], new          EventHandler(OnMenuClicked));
InBlock.gif·                        menuItem.Tag 
= command;
InBlock.gif·                        contextMenu.MenuItems.Add(menuItem);
ExpandedSubBlockEnd.gif·                     }

ExpandedBlockEnd.gif·               }

None.gif·                
None.gif·               
//  Handle the event when the MenuItem is clicked
None.gif
·                private   void  OnMenuClicked( object  sender, EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif·               
dot.gif {
InBlock.gif·                
// Retrieve the menu item that was clicked
InBlock.gif
·                MenuItem menuItem = sender as MenuItem;
InBlock.gif·                
if (menuItem != null && menuItem.Tag is MenuCommand)
ExpandedSubBlockStart.gifContractedSubBlock.gif·                     
dot.gif{
InBlock.gif·                        
// invoke the command corresponding to the menu item clicked
InBlock.gif
·                        MenuCommand command = menuItem.Tag as MenuCommand;
InBlock.gif·                        command.Invoke();
ExpandedSubBlockEnd.gif·                     }

ExpandedBlockEnd.gif·               }

None.gif


这样,在界面上就可以显示出你自己的上下文菜单了

关于菜单命令的响应处理:

None.gif ·                //  Invoke the standard command with the command id of the command clicked
None.gif
·                this .workflowDesignerControl1.InvokeStandardCommand(WorkflowMenuCommands.Expand);
None.gif·                
None.gif·               
public   void  InvokeStandardCommand(CommandID cmd)
ExpandedBlockStart.gifContractedBlock.gif·                  
dot.gif {
InBlock.gif·                     IMenuCommandService menuService 
=
InBlock.gif·                     GetService(
typeof(IMenuCommandService)) as IMenuCommandService;
InBlock.gif·                     
if (menuService != null)
InBlock.gif·                     menuService.GlobalInvoke(cmd);
ExpandedBlockEnd.gif·                  }

None.gif


https://i-blog.csdnimg.cn/blog_migrate/415b5f892e0d2abbba01d448461663ba.png


2
:生成后台代码MemberCreationService,和EventBindingService

   MemberCreationService可以用来生成关于Member,Filed的之类的定义

   EventBindingService则可以生成和设计界面上事件关联的代码的映射。比方说“CodeActivty”要执行的代码xxx_Excute函数和后台编译后的代码的关联。

None.gif ·                //  create code member method
None.gif

None.gif·               CodeMemberMethod method 
=   new  CodeMemberMethod();
None.gif
None.gif·               method.Name 
=  methodName;
None.gif
None.gif·               method.Parameters.AddRange(paramCollection);
None.gif
None.gif·               method.ReturnType 
=   new  CodeTypeReference(returnType);
None.gif
None.gif·               method.Attributes 
=  modifiers;
None.gif
None.gif·                
None.gif
None.gif·               
// push the method into the code compile unit
None.gif

None.gif·               typeDeclaration.Members.Insert(index, method);
None.gif
None.gif·                
None.gif
None.gif·               
//  refresh the code compile unit
None.gif

None.gif·               TypeProvider typeProvider 
=  (TypeProvider) this .serviceProvider.GetService( typeof (ITypeProvider));
None.gif
None.gif·               typeProvider.RefreshCodeCompileUnit(
this .ccu, new  EventHandler(RefreshCCU));
None.gif
None.gif


 其后台代码可能这样

None.gif ·                public  partial  class  Workflow1 : SequentialWorkflowActivity
ExpandedBlockStart.gifContractedBlock.gif·               
dot.gif {
InBlock.gif·                       
private void EventHandler(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif·                       
dot.gif{
ExpandedSubBlockEnd.gif·                       }

ExpandedBlockEnd.gif·               }

None.gif


xml的定义可能这样:

3:显示工具箱的ToolBoxService

  这个类继承自:IToolboxService,他可以显示工作流设计中需要的各类组件。

https://i-blog.csdnimg.cn/blog_migrate/696f4de679e21c70e6ee172509c6ca1f.png


4
:显示组件属性的ActivityBind Dialog: IPropertyValueUIService

一般使用PropertyValueUIItem来传递数据

https://i-blog.csdnimg.cn/blog_migrate/f96fc8737e44224141eb0ba2f25d45c6.png


5
Rules Dialog:用来编辑各种Rule

   这个用来编辑rule,ruleSet

https://i-blog.csdnimg.cn/blog_migrate/ed6afc2e8a7a93c4f797167636e7e105.png

 

6:处理状态机State Machine Features:

   这段代码用来处理状态机


  

  

None.gif 1 .                           //  Save the layout in case of State Machine Workflow
None.gif
2 .                           string  layoutFile  =  Path.Combine(Path.GetDirectoryName( this .xoml), Path.GetFileNameWithoutExtension( this .xoml)  +   " .layout " );
None.gif
3 .                          ActivityDesigner rootdesigner  =  host.GetDesigner(rootActivity)  as  ActivityDesigner;
None.gif
4 .                          XmlWriter layoutwriter  =  XmlWriter.Create(layoutFile);
None.gif
5 .                          IList errors  =   null ;
None.gif
6 .                          SaveDesignerLayout(layoutwriter, rootdesigner,  out  errors);
None.gif
7 .                          layoutwriter.Close();
None.gif
8 .                           
None.gif
9 .                           //  Load the layout
None.gif
10 .                        string  layoutFile  =  Path.Combine(Path.GetDirectoryName( this .xoml), Path.GetFileNameWithoutExtension( this .xoml)  +   " .layout " );
None.gif
11 .                        if  (File.Exists(layoutFile))
ExpandedBlockStart.gifContractedBlock.gif
12 .                           dot.gif {
InBlock.gif
13.                             IList loaderrors = null;
InBlock.gif
14.                      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值