博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows Workflow Foundation(一)(转载)
阅读量:6713 次
发布时间:2019-06-25

本文共 21207 字,大约阅读时间需要 70 分钟。

组织并执行一系列的操作或者活动的最自然的方式——那就是工作流——同时也是构造一个工作流程的可执行表现形式的最佳途径。
Windows Workflow Foundation(
以下简称WWF)提供了一个编程框架和工具以开发和执行各种不同的基于工作流的应用程序,比如文档管理、线型的商业应用、贸易单据流程、IT管理、B2B应用以及消费者应用。

有状态的、持久化的、不间断运行的应用程序

WWF简化了创造有状态的,不间断运行的异步工作流应用程序的过程。WWF运行时引擎管理工作流的运行,为工作流的长期运行提供保障,并能抵抗机器的重启。WWF运行时服务提供了一系列的附加功能,例如WWF服务为能温和且正确的处理错误提供了事务和持久化。

工作流模型

WWF为开发人员提供了一个工作流模型,来描述应用程序所需要的处理过程。通过使用工作流模型所提供的流程控件、状态管理、事务和同步器,开发人员可以分离应用程序逻辑和业务逻辑,构造一个高层次的抽象,达到提高开发者效率的目的。

组件的重用

WWF为开发者提供了一系列的活动——活动是一种包含了工作单元的可配置逻辑结构。这种结构封装了开发者可能经常性用到的一些部件,这样就节省了开发者的时间。

如果遇到一些特殊的需求或场景,WWF同样为开发自定义的活动提供了简单的方法。
通过将工作流引擎载入进程,WWF可以使任何应用程序和服务容器运行工作流。
运行时服务组件被设计成可插件形式的,这个可使应用程序以最合适的方式来提供它们的服务。WWF还提供了一组运行时服务的默认实现,这些服务能满足大部分类型的应用程序。
另外,WWF还提供了对ASP.NET的out-of-the-box(啥意思?)支持,让构造和运行能在IIS和ASP.NET环境的工作流变得简单。

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

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

开始构造顺序工作流

创建工作流类

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

1
None.gif
using System;
2
None.gif
using System.Workflow.Activities;
3
None.gif
using System.Workflow.Activities.Rules;
4
None.gif
5
None.gif
namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
6
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif {
7
InBlock.gif [RuleConditionsAttribute(
typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.ExpenseReportWorkflow))]
8
InBlock.gif
public
sealed partial
class ExpenseReportWorkflow : System.Workflow.Activities.SequentialWorkflow
9
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
10
InBlock.gif
public ExpenseReportWorkflow()
11
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
12
InBlock.gif
13
ExpandedSubBlockEnd.gif }
14
ExpandedSubBlockEnd.gif }
15
ExpandedBlockEnd.gif}
16
None.gif

声明工作流参数

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

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

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

ContractedBlock.gif
ExpandedBlockStart.gif
1
None.gif
public ExpenseReportWorkflow()
2
None.gif
3
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif{
4
InBlock.gif
5
InBlock.gif InitializeComponent();
6
InBlock.gif
7
ExpandedBlockEnd.gif}
8
None.gif
9
None.gif
10
None.gif
11
None.gif
private
void InitializeComponent()
12
None.gif
13
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif{
14
InBlock.gif
15
InBlock.gif System.Workflow.ComponentModel.ParameterDeclaration Amount =
new System.Workflow.ComponentModel.ParameterDeclaration();
16
InBlock.gif
17
InBlock.gif System.Workflow.ComponentModel.ParameterDeclaration Result =
new System.Workflow.ComponentModel.ParameterDeclaration();
18
InBlock.gif
19
InBlock.gif
//
20
InBlock.gif
21
InBlock.gif
//
Workflow Parameters
22
InBlock.gif
23
InBlock.gif
//
24
InBlock.gif
25
InBlock.gif Amount.Direction = System.Workflow.ComponentModel.ParameterDirection.In;
26
InBlock.gif
27
InBlock.gif Amount.Name = "Amount";
28
InBlock.gif
29
InBlock.gif Amount.Type =
typeof(
int);
30
InBlock.gif
31
InBlock.gif Amount.Value =
null;
32
InBlock.gif
33
InBlock.gif Result.Direction = System.Workflow.ComponentModel.ParameterDirection.Out;
34
InBlock.gif
35
InBlock.gif Result.Name = "Result";
36
InBlock.gif
37
InBlock.gif Result.Type =
typeof(
string);
38
InBlock.gif
39
InBlock.gif Result.Value =
null;
40
InBlock.gif
41
InBlock.gif
this.Parameters.Add(Amount);
42
InBlock.gif
43
InBlock.gif
this.Parameters.Add(Result);
44
InBlock.gif
45
ExpandedBlockEnd.gif}
46
None.gif
47
None.gif

使用IfElse活动

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

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

创建IfElse活动

1.定义4个私有变量

类型

名称

IfElse

evaluateExpenseReportAmount

IfElseBranch

ifNeedsLeadApproval

IfElseBranch

elseNeedsManagerApproval

CodeCondition

ifElseLogicStatement

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

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

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

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

1
None.gif
private
bool DetermineApprovalContact(
object sender, EventArgs e)
2
None.gif
3
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif {
4
InBlock.gif
5
InBlock.gif
if ( Convert.ToInt32(
this.Parameters["Amount"].Value) < 1000 )
6
InBlock.gif
7
InBlock.gif
return
true ;
8
InBlock.gif
9
InBlock.gif
10
InBlock.gif
11
InBlock.gif
return
false ;
12
InBlock.gif
13
ExpandedBlockEnd.gif}
14
None.gif

构造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
None.gif
//
2
None.gif
3
None.gif
//
invokeGetLeadApproval
4
None.gif
5
None.gif
//
6
None.gif
7
None.gif
this.invokeGetLeadApproval.ID = "invokeGetLeadApproval" ;
8
None.gif
9
None.gif
this.invokeGetLeadApproval.InterfaceType =
typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
10
None.gif
11
None.gif
this.invokeGetLeadApproval.MethodName = "GetLeadApproval" ;
12
None.gif
13
None.gif
//
14
None.gif
15
None.gif
//
invokeGetManagerApproval
16
None.gif
17
None.gif
//
18
None.gif
19
None.gif
this.invokeGetManagerApproval.ID = "invokeGetManagerApproval" ;
20
None.gif
21
None.gif
this.invokeGetManagerApproval.InterfaceType =
typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
22
None.gif
23
None.gif
this.invokeGetManagerApproval.MethodName = "GetManagerApproval" ;
24
None.gif
25
None.gif

以下代码定义了IExpenseReportService接口

1
None.gif
using System;
2
None.gif
3
None.gif
using System.Workflow.ComponentModel;
4
None.gif
5
None.gif
using System.Workflow.Runtime.Messaging;
6
None.gif
7
None.gif
8
None.gif
9
None.gif
namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
10
None.gif
11
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif {
12
InBlock.gif
13
InBlock.gif [DataExchangeService]
14
InBlock.gif
15
InBlock.gif
public
interface IExpenseReportService
16
InBlock.gif
17
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
18
InBlock.gif
19
InBlock.gif
void GetLeadApproval();
20
InBlock.gif
21
InBlock.gif
void GetManagerApproval();
22
InBlock.gif
23
InBlock.gif
event EventHandler<WorkflowMessageEventArgs> ExpenseReportApproved;
24
InBlock.gif
25
InBlock.gif
event EventHandler<WorkflowMessageEventArgs> ExpenseReportRejected;
26
InBlock.gif
27
ExpandedSubBlockEnd.gif }
28
InBlock.gif
29
ExpandedBlockEnd.gif}
30
None.gif
31
None.gif

监听宿主事件

在这个阶段,工作流已经从宿主程序接受了两个参数(译者注:其中一个为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
None.gif
//
2
None.gif
3
None.gif
//
listenApproveReject
4
None.gif
5
None.gif
//
6
None.gif
7
None.gif
this.listenApproveReject.Activities.Add(
this .approveEventDriven);
8
None.gif
9
None.gif
this.listenApproveReject.Activities.Add(
this .rejectEventDriven);
10
None.gif
11
None.gif
this.listenApproveReject.ID = "listenApproveReject" ;
12
None.gif
13
None.gif
//
14
None.gif
15
None.gif
//
approveEventDriven
16
None.gif
17
None.gif
//
18
None.gif
19
None.gif
this.approveEventDriven.Activities.Add(
this .approveEvent);
20
None.gif
21
None.gif
this.approveEventDriven.ID = "approveEventDriven" ;
22
None.gif
23
None.gif
//
24
None.gif
25
None.gif
//
approveEvent
26
None.gif
27
None.gif
//
28
None.gif
29
None.gif
this.approveEvent.EventName = "ExpenseReportApproved" ;
30
None.gif
31
None.gif
this.approveEvent.ID = "approveEvent" ;
32
None.gif
33
None.gif
this.approveEvent.InterfaceType =
typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
34
None.gif
35
None.gif
this.approveEvent.Roles =
null ;
36
None.gif
37
None.gif
this.approveEvent.Invoked +=
new System.EventHandler(
this .approveEvent_Invoked);
38
None.gif
39
None.gif
//
40
None.gif
41
None.gif
//
rejectEventDriven
42
None.gif
43
None.gif
//
44
None.gif
45
None.gif
this.rejectEventDriven.Activities.Add(
this .rejectEvent);
46
None.gif
47
None.gif
this.rejectEventDriven.ID = "rejectEventDriven" ;
48
None.gif
49
None.gif
//
50
None.gif
51
None.gif
//
rejectEvent
52
None.gif
53
None.gif
//
54
None.gif
55
None.gif
this.rejectEvent.EventName = "ExpenseReportRejected" ;
56
None.gif
57
None.gif
this.rejectEvent.ID = "rejectEvent" ;
58
None.gif
59
None.gif
this.rejectEvent.InterfaceType =
typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
60
None.gif
61
None.gif
this.rejectEvent.Roles =
null ;
62
None.gif
63
None.gif
this.rejectEvent.Invoked +=
new System.EventHandler(
this .rejectEvent_Invoked);
64
None.gif
65
None.gif

使用EventSinkActivity时,为了在工作流中加入一些附加逻辑,你可以为Invoked事件创建一个事件处理程序。一下是事件处理程序的代码

1
None.gif
private
void approveEvent_Invoked(
object sender, EventArgs e)
2
None.gif
3
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif {
4
InBlock.gif
5
InBlock.gif
this.Parameters["Result"].Value = "Report Approved" ;
6
InBlock.gif
7
ExpandedBlockEnd.gif}
8
None.gif
9
None.gif
10
None.gif
11
None.gif
private
void rejectEvent_Invoked(
object sender, EventArgs e)
12
None.gif
13
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif {
14
InBlock.gif
15
InBlock.gif
this.Parameters["Result"].Value = "Report Rejected" ;
16
InBlock.gif
17
ExpandedBlockEnd.gif}
18
None.gif
19
None.gif

完成顺序工作流

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

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

创建宿主程序

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

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

1
None.gif
using System;
2
None.gif
3
None.gif
using System.ComponentModel;
4
None.gif
5
None.gif
using System.Drawing;
6
None.gif
7
None.gif
using System.Windows.Forms;
8
None.gif
9
None.gif
using System.Collections.Generic;
10
None.gif
11
None.gif
using System.Workflow.Runtime;
12
None.gif
13
None.gif
using System.Workflow.Runtime.Hosting;
14
None.gif
15
None.gif
using System.Workflow.Runtime.Messaging;
16
None.gif
17
None.gif
18
None.gif
19
None.gif
namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflowHost
20
None.gif
21
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif {
22
InBlock.gif
23
InBlock.gif
public
class MainForm : Form, Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService
24
InBlock.gif
25
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
26
InBlock.gif
27
InBlock.gif
private System.Windows.Forms.Label label1;
28
InBlock.gif
29
InBlock.gif
private System.Windows.Forms.TextBox result;
30
InBlock.gif
31
InBlock.gif
private System.Windows.Forms.Label label2;
32
InBlock.gif
33
InBlock.gif
private System.Windows.Forms.Button submitButton;
34
InBlock.gif
35
InBlock.gif
private System.Windows.Forms.Label approvalState;
36
InBlock.gif
37
InBlock.gif
private System.Windows.Forms.Button approveButton;
38
InBlock.gif
39
InBlock.gif
private System.Windows.Forms.Button rejectButton;
40
InBlock.gif
41
InBlock.gif
private System.Windows.Forms.TextBox amount;
42
InBlock.gif
43
InBlock.gif
private System.Windows.Forms.Panel panel1;
44
InBlock.gif
45
InBlock.gif
46
InBlock.gif
47
InBlock.gif
private System.ComponentModel.IContainer components =
null ;
48
InBlock.gif
49
InBlock.gif
50
InBlock.gif
51
InBlock.gif
private
delegate
void GetApprovalDelegate();
52
InBlock.gif
53
InBlock.gif
private WorkflowRuntime workflowRuntime =
null ;
54
InBlock.gif
55
InBlock.gif
private WorkflowInstance workflowInstance =
null ;
56
InBlock.gif
57
InBlock.gif
58
InBlock.gif
59
InBlock.gif
public MainForm()
60
InBlock.gif
61
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
62
InBlock.gif
63
InBlock.gif InitializeComponent();
64
InBlock.gif
65
InBlock.gif
66
InBlock.gif
67
InBlock.gif
//
Collapse approve/reject panel
68
InBlock.gif
69
InBlock.gif
this.Height -=
this .panel1.Height;
70
InBlock.gif
71
InBlock.gif
72
InBlock.gif
73
InBlock.gif workflowRuntime =
new WorkflowRuntime();
74
InBlock.gif
75
InBlock.gif workflowRuntime.AddService(
this );
76
InBlock.gif
77
InBlock.gif workflowRuntime.StartRuntime();
78
InBlock.gif
79
InBlock.gif
80
InBlock.gif
81
InBlock.gif workflowRuntime.WorkflowCompleted +=
new EventHandler<WorkflowCompletedEventArgs> (workflowRuntime_WorkflowCompleted);
82
InBlock.gif
83
ExpandedSubBlockEnd.gif }
84
InBlock.gif
85
InBlock.gif
86
InBlock.gif
87
InBlock.gif
protected
override
void Dispose(
bool disposing)
88
InBlock.gif
89
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
90
InBlock.gif
91
InBlock.gif
if (disposing && (components !=
null ))
92
InBlock.gif
93
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
94
InBlock.gif
95
InBlock.gif components.Dispose();
96
InBlock.gif
97
ExpandedSubBlockEnd.gif }
98
InBlock.gif
99
InBlock.gif
base .Dispose(disposing);
100
InBlock.gif
101
ExpandedSubBlockEnd.gif }
102
InBlock.gif
103
InBlock.gif
104
InBlock.gif
105
InBlock.gif
private
void InitializeComponent()
106
InBlock.gif
107
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
108
InBlock.gif
109
InBlock.gif
this.label1 =
new System.Windows.Forms.Label();
110
InBlock.gif
111
InBlock.gif
this.result =
new System.Windows.Forms.TextBox();
112
InBlock.gif
113
InBlock.gif
this.label2 =
new System.Windows.Forms.Label();
114
InBlock.gif
115
InBlock.gif
this.submitButton =
new System.Windows.Forms.Button();
116
InBlock.gif
117
InBlock.gif
this.approvalState =
new System.Windows.Forms.Label();
118
InBlock.gif
119
InBlock.gif
this.approveButton =
new System.Windows.Forms.Button();
120
InBlock.gif
121
InBlock.gif
this.rejectButton =
new System.Windows.Forms.Button();
122
InBlock.gif
123
InBlock.gif
this.amount =
new System.Windows.Forms.TextBox();
124
InBlock.gif
125
InBlock.gif
this.panel1 =
new System.Windows.Forms.Panel();
126
InBlock.gif
127
InBlock.gif
this .panel1.SuspendLayout();
128
InBlock.gif
129
InBlock.gif
this .SuspendLayout();
130
InBlock.gif
131
InBlock.gif
//
132
InBlock.gif
133
InBlock.gif
//
label1
134
InBlock.gif
135
InBlock.gif
//
136
InBlock.gif
137
InBlock.gif
this.label1.AutoSize =
true ;
138
InBlock.gif
139
InBlock.gif
this.label1.Location =
new System.Drawing.Point(13, 13 );
140
InBlock.gif
141
InBlock.gif
this.label1.Name = "label1" ;
142
InBlock.gif
143
InBlock.gif
this.label1.Size =
new System.Drawing.Size(39, 13 );
144
InBlock.gif
145
InBlock.gif
this.label1.TabIndex = 1 ;
146
InBlock.gif
147
InBlock.gif
this.label1.Text = "Amount" ;
148
InBlock.gif
149
InBlock.gif
//
150
InBlock.gif
151
InBlock.gif
//
result
152
InBlock.gif
153
InBlock.gif
//
154
InBlock.gif
155
InBlock.gif
this.result.Location =
new System.Drawing.Point(13, 69 );
156
InBlock.gif
157
InBlock.gif
this.result.Name = "result" ;
158
InBlock.gif
159
InBlock.gif
this.result.ReadOnly =
true ;
160
InBlock.gif
161
InBlock.gif
this.result.Size =
new System.Drawing.Size(162, 20 );
162
InBlock.gif
163
InBlock.gif
this.result.TabIndex = 1 ;
164
InBlock.gif
165
InBlock.gif
this.result.TabStop =
false ;
166
InBlock.gif
167
InBlock.gif
//
168
InBlock.gif
169
InBlock.gif
//
label2
170
InBlock.gif
171
InBlock.gif
//
172
InBlock.gif
173
InBlock.gif
this.label2.AutoSize =
true ;
174
InBlock.gif
175
InBlock.gif
this.label2.Location =
new System.Drawing.Point(13, 54 );
176
InBlock.gif
177
InBlock.gif
this.label2.Name = "label2" ;
178
InBlock.gif
179
InBlock.gif
this.label2.Size =
new System.Drawing.Size(33, 13 );
180
InBlock.gif
181
InBlock.gif
this.label2.TabIndex = 3 ;
182
InBlock.gif
183
InBlock.gif
this.label2.Text = "Result" ;
184
InBlock.gif
185
InBlock.gif
//
186
InBlock.gif
187
InBlock.gif
//
submitButton
188
InBlock.gif
189
InBlock.gif
//
190
InBlock.gif
191
InBlock.gif
this.submitButton.Enabled =
false ;
192
InBlock.gif
193
InBlock.gif
this.submitButton.Location =
new System.Drawing.Point(56, 95 );
194
InBlock.gif
195
InBlock.gif
this.submitButton.Name = "submitButton" ;
196
InBlock.gif
197
InBlock.gif
this.submitButton.Size =
new System.Drawing.Size(75, 23 );
198
InBlock.gif
199
InBlock.gif
this.submitButton.TabIndex = 2 ;
200
InBlock.gif
201
InBlock.gif
this.submitButton.Text = "Submit" ;
202
InBlock.gif
203
InBlock.gif
this.submitButton.Click +=
new System.EventHandler(
this .submitButton_Click);
204
InBlock.gif
205
InBlock.gif
//
206
InBlock.gif
207
InBlock.gif
//
approvalState
208
InBlock.gif
209
InBlock.gif
//
210
InBlock.gif
211
InBlock.gif
this.approvalState.AutoSize =
true ;
212
InBlock.gif
213
InBlock.gif
this.approvalState.Location =
new System.Drawing.Point(10, 9 );
214
InBlock.gif
215
InBlock.gif
this.approvalState.Name = "approvalState" ;
216
InBlock.gif
217
InBlock.gif
this.approvalState.Size =
new System.Drawing.Size(45, 13 );
218
InBlock.gif
219
InBlock.gif
this.approvalState.TabIndex = 4 ;
220
InBlock.gif
221
InBlock.gif
this.approvalState.Text = "Approval" ;
222
InBlock.gif
223
InBlock.gif
//
224
InBlock.gif
225
InBlock.gif
//
approveButton
226
InBlock.gif
227
InBlock.gif
//
228
InBlock.gif
229
InBlock.gif
this.approveButton.Enabled =
false ;
230
InBlock.gif
231
InBlock.gif
this.approveButton.Location =
new System.Drawing.Point(11, 25 );
232
InBlock.gif
233
InBlock.gif
this.approveButton.Name = "approveButton" ;
234
InBlock.gif
235
InBlock.gif
this.approveButton.Size =
new System.Drawing.Size(75, 23 );
236
InBlock.gif
237
InBlock.gif
this.approveButton.TabIndex = 0 ;
238
InBlock.gif
239
InBlock.gif
this.approveButton.Text = "Approve" ;
240
InBlock.gif
241
InBlock.gif
this.approveButton.Click +=
new System.EventHandler(
this .approveButton_Click);
242
InBlock.gif
243
InBlock.gif
//
244
InBlock.gif
245
InBlock.gif
//
rejectButton
246
InBlock.gif
247
InBlock.gif
//
248
InBlock.gif
249
InBlock.gif
this.rejectButton.Enabled =
false ;
250
InBlock.gif
251
InBlock.gif
this.rejectButton.Location =
new System.Drawing.Point(86, 25 );
252
InBlock.gif
253
InBlock.gif
this.rejectButton.Name = "rejectButton" ;
254
InBlock.gif
255
InBlock.gif
this.rejectButton.Size =
new System.Drawing.Size(75, 23 );
256
InBlock.gif
257
InBlock.gif
this.rejectButton.TabIndex = 1 ;
258
InBlock.gif
259
InBlock.gif
this.rejectButton.Text = "Reject" ;
260
InBlock.gif
261
InBlock.gif
this.rejectButton.Click +=
new System.EventHandler(
this .rejectButton_Click);
262
InBlock.gif
263
InBlock.gif
//
264
InBlock.gif
265
InBlock.gif
//
amount
266
InBlock.gif
267
InBlock.gif
//
268
InBlock.gif
269
InBlock.gif
this.amount.Location =
new System.Drawing.Point(13, 29 );
270
InBlock.gif
271
InBlock.gif
this.amount.MaxLength = 9 ;
272
InBlock.gif
273
InBlock.gif
this.amount.Name = "amount" ;
274
InBlock.gif
275
InBlock.gif
this.amount.Size =
new System.Drawing.Size(162, 20 );
276
InBlock.gif
277
InBlock.gif
this.amount.TabIndex = 0 ;
278
InBlock.gif
279
InBlock.gif
this.amount.KeyPress +=
new System.Windows.Forms.KeyPressEventHandler(
this .amount_KeyPress);
280
InBlock.gif
281
InBlock.gif
this.amount.TextChanged +=
new System.EventHandler(
this .amount_TextChanged);
282
InBlock.gif
283
InBlock.gif
//
284
InBlock.gif
285
InBlock.gif
//
panel1
286
InBlock.gif
287
InBlock.gif
//
288
InBlock.gif
289
InBlock.gif
this.panel1.Controls.Add(
this .approvalState);
290
InBlock.gif
291
InBlock.gif
this.panel1.Controls.Add(
this .approveButton);
292
InBlock.gif
293
InBlock.gif
this.panel1.Controls.Add(
this .rejectButton);
294
InBlock.gif
295
InBlock.gif
this.panel1.Location =
new System.Drawing.Point(3, 124 );
296
InBlock.gif
297
InBlock.gif
this.panel1.Name = "panel1" ;
298
InBlock.gif
299
InBlock.gif
this.panel1.Size =
new System.Drawing.Size(172, 66 );
300
InBlock.gif
301
InBlock.gif
this.panel1.TabIndex = 8 ;
302
InBlock.gif
303
InBlock.gif
//
304
InBlock.gif
305
InBlock.gif
//
MainForm
306
InBlock.gif
307
InBlock.gif
//
308
InBlock.gif
309
InBlock.gif
this.AcceptButton =
this .submitButton;
310
InBlock.gif
311
InBlock.gif
this.AutoScaleDimensions =
new System.Drawing.SizeF(6F, 13F);
312
InBlock.gif
313
InBlock.gif
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
314
InBlock.gif
315
InBlock.gif
this.ClientSize =
new System.Drawing.Size(187, 201 );
316
InBlock.gif
317
InBlock.gif
this.Controls.Add(
this .panel1);
318
InBlock.gif
319
InBlock.gif
this.Controls.Add(
this .amount);
320
InBlock.gif
321
InBlock.gif
this.Controls.Add(
this .submitButton);
322
InBlock.gif
323
InBlock.gif
this.Controls.Add(
this .label2);
324
InBlock.gif
325
InBlock.gif
this.Controls.Add(
this .result);
326
InBlock.gif
327
InBlock.gif
this.Controls.Add(
this .label1);
328
InBlock.gif
329
InBlock.gif
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
330
InBlock.gif
331
InBlock.gif
this.MaximizeBox =
false ;
332
InBlock.gif
333
InBlock.gif
this.MinimizeBox =
false ;
334
InBlock.gif
335
InBlock.gif
this.Name = "MainForm" ;
336
InBlock.gif
337
InBlock.gif
this.Text = "Simple Expense Report" ;
338
InBlock.gif
339
InBlock.gif
this.panel1.ResumeLayout(
false );
340
InBlock.gif
341
InBlock.gif
this .panel1.PerformLayout();
342
InBlock.gif
343
InBlock.gif
this.ResumeLayout(
false );
344
InBlock.gif
345
InBlock.gif
this .PerformLayout();
346
InBlock.gif
347
InBlock.gif
348
InBlock.gif
349
ExpandedSubBlockEnd.gif }
350
InBlock.gif
351
InBlock.gif
352
InBlock.gif
353
InBlock.gif
private
void submitButton_Click(
object sender, EventArgs e)
354
InBlock.gif
355
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
356
InBlock.gif
357
InBlock.gif Type type =
typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.ExpenseReportWorkflow);
358
InBlock.gif
359
InBlock.gif
360
InBlock.gif
361
InBlock.gif
//
Construct workflow parameters
362
InBlock.gif
363
InBlock.gif Dictionary<
string,
object> properties =
new Dictionary<
string,
object> ();
364
InBlock.gif
365
InBlock.gif properties.Add("Amount", Int32.Parse(
this .amount.Text));
366
InBlock.gif
367
InBlock.gif properties.Add("Result",
string .Empty);
368
InBlock.gif
369
InBlock.gif
370
InBlock.gif
371
InBlock.gif
//
Start the workflow
372
InBlock.gif
373
InBlock.gif workflowInstance = workflowRuntime.StartWorkflow(type, properties);
374
InBlock.gif
375
ExpandedSubBlockEnd.gif }
376
InBlock.gif
377
InBlock.gif
378
InBlock.gif
379
InBlock.gif
void workflowRuntime_WorkflowCompleted(
object sender, WorkflowCompletedEventArgs e)
380
InBlock.gif
381
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
382
InBlock.gif
383
InBlock.gif
if (
this .result.InvokeRequired)
384
InBlock.gif
385
InBlock.gif
this.result.Invoke(
new EventHandler<WorkflowCompletedEventArgs>(
this .workflowRuntime_WorkflowCompleted), sender, e);
386
InBlock.gif
387
InBlock.gif
else
388
InBlock.gif
389
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
390
InBlock.gif
391
InBlock.gif
this.result.Text = e.OutputParameters["Result" ].ToString();
392
InBlock.gif
393
InBlock.gif
394
InBlock.gif
395
InBlock.gif
//
Clear fields
396
InBlock.gif
397
InBlock.gif
this.amount.Text =
string .Empty;
398
InBlock.gif
399
InBlock.gif
400
InBlock.gif
401
InBlock.gif
//
Disable buttons
402
InBlock.gif
403
InBlock.gif
this.approveButton.Enabled =
false ;
404
InBlock.gif
405
InBlock.gif
this.rejectButton.Enabled =
false ;
406
InBlock.gif
407
ExpandedSubBlockEnd.gif }
408
InBlock.gif
409
ExpandedSubBlockEnd.gif }
410
InBlock.gif
411
InBlock.gif
412
InBlock.gif
413
InBlock.gif
private
void approveButton_Click(
object sender, EventArgs e)
414
InBlock.gif
415
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
416
InBlock.gif
417
InBlock.gif
//
Raise the ExpenseReportApproved event back to the workflow
418
InBlock.gif
419
InBlock.gif ExpenseReportApproved(
null,
new WorkflowMessageEventArgs(
this .workflowInstance.InstanceId));
420
InBlock.gif
421
InBlock.gif
this.Height -=
this .panel1.Height;
422
InBlock.gif
423
InBlock.gif
this.submitButton.Enabled =
true ;
424
InBlock.gif
425
ExpandedSubBlockEnd.gif }
426
InBlock.gif
427
InBlock.gif
428
InBlock.gif
429
InBlock.gif
private
void rejectButton_Click(
object sender, EventArgs e)
430
InBlock.gif
431
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
432
InBlock.gif
433
InBlock.gif
//
Raise the ExpenseReportRejected event back to the workflow
434
InBlock.gif
435
InBlock.gif ExpenseReportRejected(
null,
new WorkflowMessageEventArgs(
this .workflowInstance.InstanceId));
436
InBlock.gif
437
InBlock.gif
this.Height -=
this .panel1.Height;
438
InBlock.gif
439
InBlock.gif
this.submitButton.Enabled =
true ;
440
InBlock.gif
441
ExpandedSubBlockEnd.gif }
442
InBlock.gif
443
InBlock.gif
444
InBlock.gif
445
ContractedSubBlock.gif
ExpandedSubBlockStart.gif
IExpenseReportService Members
#region IExpenseReportService Members
446
InBlock.gif
447
InBlock.gif
448
InBlock.gif
449
InBlock.gif
public
void GetLeadApproval()
450
InBlock.gif
451
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
452
InBlock.gif
453
InBlock.gif
if (
this.approvalState.InvokeRequired)
454
InBlock.gif
455
InBlock.gif
this.approvalState.Invoke(
new GetApprovalDelegate(
this.GetLeadApproval));
456
InBlock.gif
457
InBlock.gif
else
458
InBlock.gif
459
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
460
InBlock.gif
461
InBlock.gif
this.approvalState.Text = "Lead approval needed";
462
InBlock.gif
463
InBlock.gif
this.approveButton.Enabled =
true;
464
InBlock.gif
465
InBlock.gif
this.rejectButton.Enabled =
true;
466
InBlock.gif
467
InBlock.gif
468
InBlock.gif
469
InBlock.gif
//
expand the panel
470
InBlock.gif
471
InBlock.gif
this.Height +=
this.panel1.Height;
472
InBlock.gif
473
InBlock.gif
this.submitButton.Enabled =
false;
474
InBlock.gif
475
ExpandedSubBlockEnd.gif }
476
InBlock.gif
477
ExpandedSubBlockEnd.gif }
478
InBlock.gif
479
InBlock.gif
480
InBlock.gif
481
InBlock.gif
public
void GetManagerApproval()
482
InBlock.gif
483
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
484
InBlock.gif
485
InBlock.gif
if (
this.approvalState.InvokeRequired)
486
InBlock.gif
487
InBlock.gif
this.approvalState.Invoke(
new GetApprovalDelegate(
this.GetManagerApproval));
488
InBlock.gif
489
InBlock.gif
else
490
InBlock.gif
491
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
492
InBlock.gif
493
InBlock.gif
this.approvalState.Text = "Manager approval needed";
494
InBlock.gif
495
InBlock.gif
this.approveButton.Enabled =
true;
496
InBlock.gif
497
InBlock.gif
this.rejectButton.Enabled =
true;
498
InBlock.gif
499
InBlock.gif
500
InBlock.gif
501
InBlock.gif
//
expand the panel
502
InBlock.gif
503
InBlock.gif
this.Height +=
this.panel1.Height;
504
InBlock.gif
505
InBlock.gif
this.submitButton.Enabled =
false;
506
InBlock.gif
507
ExpandedSubBlockEnd.gif }
508
InBlock.gif
509
ExpandedSubBlockEnd.gif }
510
InBlock.gif
511
InBlock.gif
512
InBlock.gif
513
InBlock.gif
public
event EventHandler<WorkflowMessageEventArgs> ExpenseReportApproved;
514
InBlock.gif
515
InBlock.gif
public
event EventHandler<WorkflowMessageEventArgs> ExpenseReportRejected;
516
InBlock.gif
517
InBlock.gif
518
InBlock.gif
519
ExpandedSubBlockEnd.gif
#endregion
520
InBlock.gif
521
InBlock.gif
522
InBlock.gif
523
InBlock.gif
private
void amount_KeyPress(
object sender, KeyPressEventArgs e)
524
InBlock.gif
525
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
526
InBlock.gif
527
InBlock.gif
if (!Char.IsControl(e.KeyChar) && (! Char.IsDigit(e.KeyChar)))
528
InBlock.gif
529
InBlock.gif e.KeyChar = Char.MinValue;
530
InBlock.gif
531
ExpandedSubBlockEnd.gif }
532
InBlock.gif
533
InBlock.gif
534
InBlock.gif
535
InBlock.gif
private
void amount_TextChanged(
object sender, EventArgs e)
536
InBlock.gif
537
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
538
InBlock.gif
539
InBlock.gif submitButton.Enabled = amount.Text.Length > 0 ;
540
InBlock.gif
541
ExpandedSubBlockEnd.gif }
542
InBlock.gif
543
ExpandedSubBlockEnd.gif }
544
InBlock.gif
545
InBlock.gif
546
InBlock.gif
547
InBlock.gif
static
class Program
548
InBlock.gif
549
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
550
InBlock.gif
551
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
<summary>
552
InBlock.gif
553
InBlock.gif
///
The main entry point for the application.
554
InBlock.gif
555
ExpandedSubBlockEnd.gif
///
</summary>
556
InBlock.gif
557
InBlock.gif [STAThread]
558
InBlock.gif
559
InBlock.gif
static
void Main()
560
InBlock.gif
561
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif {
562
InBlock.gif
563
InBlock.gif Application.EnableVisualStyles();
564
InBlock.gif
565
InBlock.gif Application.Run(
new MainForm());
566
InBlock.gif
567
ExpandedSubBlockEnd.gif }
568
InBlock.gif
569
ExpandedSubBlockEnd.gif }
570
InBlock.gif
571
ExpandedBlockEnd.gif}
572
None.gif
573
None.gif

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

那就是IfElseBranch中的InvokeMethodActivity。

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

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

workflowRuntime = new WorkflowRuntime();

workflowRuntime.AddService(this);

workflowRuntime.StartRuntime();

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

另外,注册服务不一定要用AddService,也可以用WorkflowRuntime.StartWorkflow(Type)。

本文转自高海东博客园博客,原文链接:http://www.cnblogs.com/ghd258/archive/2005/12/18/299437.html,如需转载请自行联系原作者

你可能感兴趣的文章
《CMYK 2.0——设计师色彩管理手册》—第1章1.3节副作用
查看>>
java.util.concurrent.locks.LockSupport
查看>>
红帽加入 Node.js 基金会白金会员
查看>>
《OpenGL编程指南》一2.7 独立的着色器对象
查看>>
Ionic 3.4.2 发布,漂亮的 HTML5 移动应用框架
查看>>
Linux Kernel 4.9-rc8,4.9 分支最后一个候选版
查看>>
想开发 Android 分支?没门!
查看>>
《Web异步与实时交互——iframe AJAX WebSocket开发实战》—— 2.2 相关关键技术及工作原理...
查看>>
《Nmap渗透测试指南》—第1章1.5节Mac OS安
查看>>
重磅,企业实施大数据的路径
查看>>
linux之cp/scp命令+scp命令详解
查看>>
Spark 源码分析 -- BlockStore
查看>>
《C语言编程初学者指南》一1.7 创建并运行第一个C程序
查看>>
学习和使用 PHP 应该注意的10件事
查看>>
《Ember.js实战》——2.5 Ember.js对象模型
查看>>
《响应式Web图形设计》一第13章 响应Web设计中的图像
查看>>
shiro session 监听
查看>>
定时任务框架Quartz的新玩法
查看>>
段前缀的使用(0504)
查看>>
.NET Framework 源码
查看>>