0
点赞
收藏
分享

微信扫一扫

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


注:

l         这是一篇翻译

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()OnPaint()),还提供诸如SaveWorkflowAsImage()之类的函数。


 

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

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





·                           

internal   sealed   class  WorkflowLoader : WorkflowDesignerLoader

·                           


{

·                              protected override void PerformLoad(IDesignerSerializationManager serializationManager)

·                                 

{

·                                    base.PerformLoad(serializationManager);

·                                    // Implement the logic to read from the serialized state,

·                                    // create the activity tree and the corresponding designer

·                                    // tree and add it to the designer host

·                                 }

·                            

·                              protected override void PerformFlush(IDesignerSerializationManager manager)

·                                 

{

·                                    // Implement the logic to save the activity tree to a

·                                    // serialized state along with any code beside elements 

·                                 }

·                           }



加载工作流,显示



·                            //

 Create new Design surface and loader (created as shown above)

·                            

·                           DesignSurface designSurface  =

  new  DesignSurface();

·                           WorkflowLoader loader  =

  new  WorkflowLoader();

·                            

·                            //

 load the design surface using the loader. This will call the

·                            //  PerformLoad method on the loader, create the activity tree and

·                            //  add the corresponding designer components to the designer host

·                            

·                           designSurface.BeginLoad(loader);

·                            

·                            //

 Get the designer host and retrieve the corresponding root component

·                           IDesignerHost designerHost  =  designSurface.GetService( typeof (IDesignerHost))  as  IDesignerHost;

·                            if

 (designerHost  !=   null   &&  designerHost.RootComponent  !=   null )

·                           

{

·                              // Get the designer associated with the root component

·                              IRootDesigner rootDesigner =    designerHost.GetDesigner(designerHost.RootComponent) as IRootDesigner;

·                              if (rootDesigner != null)

·                              

{

·                                 this.designSurface = designSurface;

·                                 this.loader = loader;

·                              

·                                    // Assign the default view of the rootdesigner to WorkflowView

·                                    this.workflowView = rootDesigner.GetView(ViewTechnology.Default) as          WorkflowView;

·                            

·                                    // Add the workflow view control to winforms app

·                                    this.workflowViewSplitter.Panel1.Controls.Add(this.workflowView);

·                                    this.workflowView.Focus();

·                                    this.propertyGrid.Site = designerHost.RootComponent.Site;

·                              }

·                            }


 

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

​​http://msdn2.microsoft.com/en-us/library/Aa480213.wfdsgnrehst02(en-us,MSDN.10).gif​​


 

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


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

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

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



·                //  Create a new context menu


·               ContextMenu contextMenu  =   new  ContextMenu();

·               Dictionary < CommandID, 

string >  selectionCommands  =   new  Dictionary < CommandID,  string > ();

·                

·                //  Add the required commands


·               selectionCommands.Add(WorkflowMenuCommands.Cut,  " Cut " );

·               selectionCommands.Add(WorkflowMenuCommands.Copy,  " Copy

" );

·               selectionCommands.Add(WorkflowMenuCommands.Paste,  " Paste

" );

·               selectionCommands.Add(WorkflowMenuCommands.Delete,  " Delete

" );

·                foreach  (CommandID id 

in  selectionCommands.Keys)

·               

{

·                     MenuCommand command = FindCommand(id);

·                     if (command != null)

·                      

{

·                        // For each command create a new menu item and add an

·                        MenuItem menuItem = new MenuItem(selectionCommands[id], new          EventHandler(OnMenuClicked));

·                        menuItem.Tag = command;

·                        contextMenu.MenuItems.Add(menuItem);

·                     }

·               }

·                

·                //  Handle the event when the MenuItem is clicked


·                private   void  OnMenuClicked( object  sender, EventArgs e)

·               

{

·                // Retrieve the menu item that was clicked

·                MenuItem menuItem = sender as MenuItem;

·                if (menuItem != null && menuItem.Tag is MenuCommand)

·                     

{

·                        // invoke the command corresponding to the menu item clicked

·                        MenuCommand command = menuItem.Tag as MenuCommand;

·                        command.Invoke();

·                     }

·               }


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

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



·                //  Invoke the standard command with the command id of the command clicked

·                this .workflowDesignerControl1.InvokeStandardCommand(WorkflowMenuCommands.Expand);

·                

·                public   void

 InvokeStandardCommand(CommandID cmd)

·                  

{

·                     IMenuCommandService menuService =

·                     GetService(typeof(IMenuCommandService)) as IMenuCommandService;

·                     if (menuService != null)

·                     menuService.GlobalInvoke(cmd);

·                  }


​​http://msdn2.microsoft.com/en-us/library/Aa480213.wfdsgnrehst03(en-us,MSDN.10).gif​​


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

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

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



·                //  create code member method


·               CodeMemberMethod method  =   new  CodeMemberMethod();


·               method.Name  =  methodName;


·               method.Parameters.AddRange(paramCollection);


·               method.ReturnType  =   new  CodeTypeReference(returnType);


·               method.Attributes  =  modifiers;


·                


·                // push the method into the code compile unit


·               typeDeclaration.Members.Insert(index, method);


·                


·                //  refresh the code compile unit


·               TypeProvider typeProvider  =  (TypeProvider) this .serviceProvider.GetService( typeof

(ITypeProvider));


·               typeProvider.RefreshCodeCompileUnit( this .ccu, new  EventHandler(RefreshCCU));



 其后台代码可能这样



·                public  partial  class  Workflow1 : SequentialWorkflowActivity

·               

{

·                       private void EventHandler(object sender, System.EventArgs e)

·                       

{

·                       }

·               }


xml的定义可能这样:

3:显示工具箱的ToolBoxService

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

​​http://msdn2.microsoft.com/en-us/library/Aa480213.wfdsgnrehst04(en-us,MSDN.10).gif​​


4:显示组件属性的ActivityBindDialog: IPropertyValueUIService

一般使用PropertyValueUIItem来传递数据

​​http://msdn2.microsoft.com/en-us/library/Aa480213.wfdsgnrehst05(en-us,MSDN.10).gif​​


5:RulesDialog:用来编辑各种Rule。

   这个用来编辑rule,ruleSet

​​http://msdn2.microsoft.com/en-us/library/Aa480213.wfdsgnrehst07(en-us,MSDN.10).gif​​


 

6:处理状态机State Machine Features:

   这段代码用来处理状态机





1 .                           //  Save the layout in case of State Machine Workflow

2 .                           string  layoutFile  =  Path.Combine(Path.GetDirectoryName( this .xoml), Path.GetFileNameWithoutExtension( this .xoml)  +   " .layout " );

3 .                          ActivityDesigner rootdesigner  =  host.GetDesigner(rootActivity)  as  ActivityDesigner;

4 .                          XmlWriter layoutwriter  =  XmlWriter.Create(layoutFile);

5 .                          IList errors  =   null ;

6 .                          SaveDesignerLayout(layoutwriter, rootdesigner,  out  errors);

7 .                          layoutwriter.Close();

8 .                           

9 .                           //  Load the layout

10 .                        string  layoutFile  =  Path.Combine(Path.GetDirectoryName( this .xoml), Path.GetFileNameWithoutExtension( this .xoml)  +   " .layout " );

11 .                        if  (File.Exists(layoutFile))

12 .                          

{

13.                             IList loaderrors = null;

14.                      

举报

相关推荐

0 条评论