注:
l 这是一篇翻译,来自http://msdn2.microsoft.com/en-us/library/aa480213.aspx
l 对于一些细节我没有完全翻译
l 增加了一些我的注释,在“[]”里面
l 主要是给朋友们介绍一下这方面的情况
Vihang Dalal
Software Development Engineer Test
Microsoft Corporation
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())
·
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类,用来装载各种服务,和向外提供各类服务接口。
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,用来显示菜单命令。这些代码用来增加一些额外的命令菜单
·
//
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);
· }
https://i-blog.csdnimg.cn/blog_migrate/415b5f892e0d2abbba01d448461663ba.png

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,他可以显示工作流设计中需要的各类组件。
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:
这段代码用来处理状态机
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. using (XmlReader xmlReader = XmlReader.Create(layoutFile))
15. LoadDesignerLayout(xmlReader, out loaderrors);
16. }
![]()
https://i-blog.csdnimg.cn/blog_migrate/18e83f338c47509b2479adb1a1ecd96b.png
7:其他功能Compile Workflow.(编译处理)
· WorkflowCompiler compiler
=
new
WorkflowCompiler();
· WorkflowCompilerParameters parameters
=
new
WorkflowCompilerParameters();
·
·
//
adding the code beside file and XAML file to the arraylist of files to
·
//
be compiled
· ArrayList files
=
new
ArrayList();
· files.Add(
this
.loader.Xoml);
· files.Add(codeBesideFile);
·
·
//
adding the rules file to the resources
·
string
resources
=
@"
/resource:
"
+
rulesFile
+
"
,
"
+
this
.NameSpace
+
"
.
"
+
this
.TypeName
+
"
.
"
+
"
rules
"
;
· parameters.CompilerOptions
+=
resources;
·
· parameters.OutputAssembly
=
"
CustomWorkflow
"
+
Guid.NewGuid().ToString()
+
"
.dll
"
;
·
·
//
Compile the workflow
· WorkflowCompilerResults results
=
compiler.Compile(parameters, strArr);

结论
WWF提供了一组API,可以让你自定义自己的脱离vs2005环境的WWF设计器。这个设计器可以提供更高性能的功能,也可给客户定制设计器,还可以提供rules support的无缝连接
更多信息
· Numerous documents and links to webcasts and labs.
· SDK Samples:
· Designer Hosting
· Outlook Workflow Wizard
· For questions related to Designer hosting or WF in general, please visit this discussion forum.

本文介绍了如何使用Windows Workflow Foundation (WWF) API来自定义设计器,使其能够在Visual Studio 2005之外独立运行。文中提供了具体的类实现示例,如WorkflowLoader、DesignSurface等,并详细解释了如何加载和显示工作流。
99

被折叠的 条评论
为什么被折叠?



