您的位置:首页 > 其它

Windows Workflow Foundation之旅(二)——指南1(创建顺序工作流)

2007-09-05 23:52 471 查看
Windows Workflow Foundation之旅(二)——指南1(构造一个顺序工作流)
翻译自 ms-help://MS.WinWF.v1.EN/WinWF_GettingStarted/html/9c3e5551-4eff-4977-89ac-f81ab092d996.htm


顺序工作流(sequential workflow)是为执行一种由一系列预定义的步骤组成的任务而设计的。这种体系结构是模拟基于过程的应用程序的。这一节将用几个步骤来编写一个简单的开支报告程序,这个小程序使用WinFrom做界面,用顺序工作流做业务逻辑。

这个小程序有一个TextBox来输入开支报告的总数,一个Button点击提交报告。工作流将评估开支,如果开支小于1000则提请领班审批,如果大于等于1000则提请经理审批。之后,工作流会发送一个审批意见,此时,出现一个Label显示审批意见,两个Button分别表示通过和拒绝审批。当某一个按钮被点击的时候,应用程序会通知回应工作流,工作流继续处理发生的事件。

开始构造顺序工作流[/b][/b]

创建工作流类[/b]

WWF SDK中定义了一个SequentialWorkFlow类,我们定义一个ExpenseRoportWorkflow类,并继承自SequentialWorkflow,这样就创建一个顺序工作流。如:

1using System;
2using System.Workflow.Activities;
3using System.Workflow.Activities.Rules;
4
5namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
6

声明工作流参数[/b]

在一个工作流运行时,它可以从宿主应用程序中接收参数。参数是ParameterDeclaration类型的对象,一旦工作流初始化完成,参数的值就能通过工作流的Parameters集合来访问。

这里的开始报告程序用了两个参数。第一个参数是开支的总数;第二个是一个传出参数,用来放置审批意见。

定义一个新的方法InitializeComponent,并在构造ExpenseRoportWorkflow类的构造函数中调用它。一下的例子示范了怎样定义两个参数并把它们加到Parameters集合中。

public ExpenseReportWorkflow()
2
3
9
10
11private void InitializeComponent()
12
13
47

使用IfElse活动[/b]

IfElse活动用条件表达式来控制工作流中流程的运行。工作流将根据条件表达式的结果来决定执行条件分支(IfElseBranch)中的哪一个活动。

例子中将使用IfElse活动。通过判断从宿主应用程序中传入的Amount参数的值是否小于1000,来决定是否将审报发送到领班,否则发送到经理。

创建IfElse活动

1.定义4个私有变量

类型

名称

IfElse

evaluateExpenseReportAmount

IfElseBranch

ifNeedsLeadApproval

IfElseBranch

elseNeedsManagerApproval

CodeCondition

ifElseLogicStatement

2.在InitializeComponent中用默认构造函数实例以上4个对象。

以下的代码示例了怎样创建IfElse活动,并用IfElseBranch活动联系两个逻辑分支。你需要把以下代码放到InitializeComponent方法底部。

1//
2
3// EvaluateExpenseReportAmount
4
5//
6
7this.EvaluateExpenseReportAmount.Activities.Add(this.ifNeedsLeadApproval);
8
9this.EvaluateExpenseReportAmount.Activities.Add(this.elseNeedsManagerApproval);
10
11this.EvaluateExpenseReportAmount.ID = "EvaluateExpenseReportAmount";
12
13//
14
15// ifNeedsLeadApproval
16
17//
18
19this.ifNeedsLeadApproval.Activities.Add(this.invokeGetLeadApproval);
20
21ifElseLogicStatement.Condition += new System.Workflow.Activities.ConditionalExpression(this.DetermineApprovalContact);
22
23this.ifNeedsLeadApproval.Condition = ifElseLogicStatement;
24
25this.ifNeedsLeadApproval.ID = "ifNeedsLeadApproval";
26
27//
28
29// elseNeedsManagerApproval
30
31//
32
33this.elseNeedsManagerApproval.Activities.Add(this.invokeGetManagerApproval);
34
35this.elseNeedsManagerApproval.Condition = null;
36
37this.elseNeedsManagerApproval.ID = "elseNeedsManagerApproval";
38

WWF在IfElse活动中,有两种评估条件表达式的方式。一种是RoleCondition,这个对象通过使用一组规则来判断条件表达式的结果;另一种就是使用CodeCondition活动。CodeCondition使用一个回调方法,这个回调方法返回一个代表评估结果的布尔值。上面的例子就是使用CodeCondition来决定条件表达式的值。如果Amount参数小于1000,回调方法返回true,否则返回false。以下的代码就是这个回调函数的定义,你可以把它加到工作流类的定义中。

1private bool DetermineApprovalContact(object sender, EventArgs e)
2
3

构造IfElse分支(IfElseBranch)活动

创建完IfElse活动之后,我们来构造IfElseBranch活动

在这个例子中,每一IfElse活动的分支都使用InvokeMethodActivity活动来通知宿主程序——工作流需要领班或经理的审批才能继续执行。InvokeMethodActivity被设计成调用一个在WWF运行时中的服务接口。我们在同一份代码文件中定义了这个接口。当我们在之后构造宿主程序时,宿主类将实现这个接口,以便能建立工作流和宿主程序的通信(这一段文档上写的很模糊,我reflect后看了源码才明白过来,在最后将补充描述一下)。

构建IfElseBranch活动

1. 在类中定义两个私有字段

类型

名称

InvokeMethodActivity

invokeGetLeadApproval

InvokeMethodActivity

invokeGetManagerApproval

2. 在InitializeComponent中用默认构造函数实例化这两个对象

以下的代码示例了怎样在父活动(IfElse)中创建IfElseBranch活动,并把两个的InvokeMethodActivity联系到对应的IfElseBranch活动上,每个InvokeMethodActivity将调用定义在IExpenseReportService接口中的方法,接口会在稍微实现。你需要把以下代码放到InitializeComponent方法底部。

1//
2
3// invokeGetLeadApproval
4
5//
6
7this.invokeGetLeadApproval.ID = "invokeGetLeadApproval";
8
9this.invokeGetLeadApproval.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
10
11this.invokeGetLeadApproval.MethodName = "GetLeadApproval";
12
13//
14
15// invokeGetManagerApproval
16
17//
18
19this.invokeGetManagerApproval.ID = "invokeGetManagerApproval";
20
21this.invokeGetManagerApproval.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
22
23this.invokeGetManagerApproval.MethodName = "GetManagerApproval";
24
25

以下代码定义了IExpenseReportService接口

1using System;
2
3using System.Workflow.ComponentModel;
4
5using System.Workflow.Runtime.Messaging;
6
7
8
9namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
10
11
31

监听宿主事件

在这个阶段,工作流已经从宿主程序接受了两个参数(译者注:其中一个为out参数,此时设为null),评估了Amount参数,作出了到底该提请谁确认审批的决定,并通知了宿主程序在继续接下来的处理之前,确认审批。这里,Listen活动和EventSinkActivity活动往往配合使用,来监听宿主程序触发指定的事件。接着,一个approval或rejection事件被引发,工作流继续执行,返回审批结果Result,并终止流程。

Listen活动的每个分支是一个EventDriven活动。EventDriven活动只能使用实现了IEventActivity接口的活动。Listen活动的每个分支中的EventDriven各有一个EventSinkActivity,它们是用来监听宿主程序触发的ExpenseReportApproved或者ExpenseReportRejected事件的。这种工作流和宿主的通信方法其实类似于之前的InvokeMethodActivity的过程,只不过前者是工作流监听宿主事件,而后者是宿主事件工作流中注册的接口。

我们已经在前面的步骤中,把接口和两个事件的定义都完成了。在这里,我们将创建一个Listen活动并和两个EventDriven分支建立连接。每个分支包含一个EventSinkActivity活动,每个EventSink监听一种对应的事件。此外,我们还将创建一些事件处理程序,来处理AfterInvoke事件(译者注:这里的AfterInvoke事件应为Invoked事件)。这些事件处理程序将会把Result参数的值设为approval或者rejected。

构造监听活动

1.在工作流类中定义5个私有字段

类型

名称

Listen

listenApproveReject

EventDriven

approveEventDriven

EventDriven

rejectEventDriven

EventSinkActivity

approveEvent

EventSinkActivity

rejectEvent

2. 在InitializeComponent中实例化。

以下的代码示例了怎样在创建Listen活动和EventSinkActivity活动,来监听宿主程序发出的事件。你需要把以下代码放到InitializeComponent方法底部。

1//
2
3// listenApproveReject
4
5//
6
7this.listenApproveReject.Activities.Add(this.approveEventDriven);
8
9this.listenApproveReject.Activities.Add(this.rejectEventDriven);
10
11this.listenApproveReject.ID = "listenApproveReject";
12
13//
14
15// approveEventDriven
16
17//
18
19this.approveEventDriven.Activities.Add(this.approveEvent);
20
21this.approveEventDriven.ID = "approveEventDriven";
22
23//
24
25// approveEvent
26
27//
28
29this.approveEvent.EventName = "ExpenseReportApproved";
30
31this.approveEvent.ID = "approveEvent";
32
33this.approveEvent.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
34
35this.approveEvent.Roles = null;
36
37this.approveEvent.Invoked += new System.EventHandler(this.approveEvent_Invoked);
38
39//
40
41// rejectEventDriven
42
43//
44
45this.rejectEventDriven.Activities.Add(this.rejectEvent);
46
47this.rejectEventDriven.ID = "rejectEventDriven";
48
49//
50
51// rejectEvent
52
53//
54
55this.rejectEvent.EventName = "ExpenseReportRejected";
56
57this.rejectEvent.ID = "rejectEvent";
58
59this.rejectEvent.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
60
61this.rejectEvent.Roles = null;
62
63this.rejectEvent.Invoked += new System.EventHandler(this.rejectEvent_Invoked);
64
65
使用EventSinkActivity时,为了在工作流中加入一些附加逻辑,你可以为Invoked事件创建一个事件处理程序。一下是事件处理程序的代码。

1private void approveEvent_Invoked(object sender, EventArgs e)
2
3
9
10
11private void rejectEvent_Invoked(object sender, EventArgs e)
12
13
19

完成顺序工作流

这个工作流包括两个主要的步骤:第一,监听宿主程序的递交审批事件,并把传入的值作为工作流参数;第二,监听通过或拒绝审批消息。一下的代码示例了怎样通过把之前创建好的活动加到工作流活动集中,来完成工作流的构造。

1//
2
3// ExpenseReportWorkflow
4
5//
6
7this.Activities.Add(this.EvaluateExpenseReportAmount);
8
9this.Activities.Add(this.listenApproveReject);
10
11this.DynamicUpdateCondition = null;
12
13this.ID = "ExpenseReportWorkflow";
14
15

创建宿主程序

WWF需要一个宿主程序来运行工作流。当程序开始运行,WWF运行时引擎也随之启动。而之前构造好的工作流,则到用户点击了Submit按钮后才真正启动。

建立一个新的源文件,取名Program。以下的代码包含了完整的WinForm应用程序。IExpenseReportService接口GetLeadApproval和GetmanagerApproval方法已经定义在另一个文件中。宿主程序实现了这个接口。在approval和rejected按钮的click事件中,将引发ExpenseReprotApproval或ExpenseReprotRejected事件。

1using System;
2
3using System.ComponentModel;
4
5using System.Drawing;
6
7using System.Windows.Forms;
8
9using System.Collections.Generic;
10
11using System.Workflow.Runtime;
12
13using System.Workflow.Runtime.Hosting;
14
15using System.Workflow.Runtime.Messaging;
16
17
18
19namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflowHost
20
21
573

Ps:上面还有个问题没有解释清楚,我reflect了一下,看了源码才知道个大概。
那就是IfElseBranch中的InvokeMethodActivity。

InvokeMethodActivity中有一个Type类型的InterfaceType属性,使用时,需要设置这个属性,并把MethodName设为这个接口中的一个方法的名称。运行时,工作流引擎(也就是WorkflowRuntime)将通过反射调用这个接口。

但引擎怎么知道调用接口的哪个实现呢?你看

workflowRuntime = new WorkflowRuntime();

workflowRuntime.AddService(this);

workflowRuntime.StartRuntime();

原来,初始化引擎时,我们已经把实现了这个interface的类型的实例(this)注册到工作流中了。运行时,引擎就遍历所有已经注册的服务,如果实现了这个接口,这调用它。

另外,可以注册一个以上的服务,工作流引擎将调用所有实现了相应接口的接口方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐