Windows Workflow Foundation(一)(转载)

组织并执行一系列的操作或者活动的最自然的方式——那就是工作流——同时也是构造一个工作流程的可执行表现形式的最佳途径。
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,这样就创建一个顺序工作流。如:

1None.gifusing System;
2None.gifusing System.Workflow.Activities;
3None.gifusing System.Workflow.Activities.Rules;
4 None.gif
5None.gifnamespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
6ExpandedBlockStart.gifContractedBlock.gifdot.gif {
7InBlock.gif [RuleConditionsAttribute(typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.ExpenseReportWorkflow))]
8InBlock.gifpublic sealed partial class ExpenseReportWorkflow : System.Workflow.Activities.SequentialWorkflow
9ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif {
10InBlock.gifpublic ExpenseReportWorkflow()
11ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif {
12 InBlock.gif
13ExpandedSubBlockEnd.gif }
14ExpandedSubBlockEnd.gif }
15ExpandedBlockEnd.gif}
16None.gif

声明工作流参数

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

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

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

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

使用IfElse活动

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

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

创建IfElse活动

1.定义4个私有变量

类型

名称

IfElse

evaluateExpenseReportAmount

IfElseBranch

ifNeedsLeadApproval

IfElseBranch

elseNeedsManagerApproval

CodeCondition

ifElseLogicStatement

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

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

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

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

1None.gifprivate bool DetermineApprovalContact(object sender, EventArgs e)
2 None.gif
3ExpandedBlockStart.gifContractedBlock.gifdot.gif {
4 InBlock.gif
5InBlock.gifif ( Convert.ToInt32(this.Parameters["Amount"].Value) < 1000 )
6 InBlock.gif
7InBlock.gifreturn true ;
8 InBlock.gif
9 InBlock.gif
10 InBlock.gif
11InBlock.gifreturn false ;
12 InBlock.gif
13ExpandedBlockEnd.gif}
14None.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方法底部。

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

以下代码定义了IExpenseReportService接口

1None.gifusing System;
2 None.gif
3None.gifusing System.Workflow.ComponentModel;
4 None.gif
5None.gifusing System.Workflow.Runtime.Messaging;
6 None.gif
7 None.gif
8 None.gif
9None.gifnamespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
10 None.gif
11ExpandedBlockStart.gifContractedBlock.gifdot.gif {
12 InBlock.gif
13 InBlock.gif [DataExchangeService]
14 InBlock.gif
15InBlock.gifpublic interface IExpenseReportService
16 InBlock.gif
17ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif {
18 InBlock.gif
19InBlock.gifvoid GetLeadApproval();
20 InBlock.gif
21InBlock.gifvoid GetManagerApproval();
22 InBlock.gif
23InBlock.gifevent EventHandler<WorkflowMessageEventArgs> ExpenseReportApproved;
24 InBlock.gif
25InBlock.gifevent EventHandler<WorkflowMessageEventArgs> ExpenseReportRejected;
26 InBlock.gif
27ExpandedSubBlockEnd.gif }
28 InBlock.gif
29ExpandedBlockEnd.gif}
30 None.gif
31None.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方法底部。

1None.gif//
2 None.gif
3None.gif// listenApproveReject
4 None.gif
5None.gif//
6None.gif
7None.gifthis.listenApproveReject.Activities.Add(this .approveEventDriven);
8 None.gif
9None.gifthis.listenApproveReject.Activities.Add(this .rejectEventDriven);
10 None.gif
11None.gifthis.listenApproveReject.ID = "listenApproveReject" ;
12 None.gif
13None.gif//
14 None.gif
15None.gif// approveEventDriven
16 None.gif
17None.gif//
18None.gif
19None.gifthis.approveEventDriven.Activities.Add(this .approveEvent);
20 None.gif
21None.gifthis.approveEventDriven.ID = "approveEventDriven" ;
22 None.gif
23None.gif//
24 None.gif
25None.gif// approveEvent
26 None.gif
27None.gif//
28None.gif
29None.gifthis.approveEvent.EventName = "ExpenseReportApproved" ;
30 None.gif
31None.gifthis.approveEvent.ID = "approveEvent" ;
32 None.gif
33None.gifthis.approveEvent.InterfaceType = typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
34 None.gif
35None.gifthis.approveEvent.Roles = null ;
36 None.gif
37None.gifthis.approveEvent.Invoked += new System.EventHandler(this .approveEvent_Invoked);
38 None.gif
39None.gif//
40 None.gif
41None.gif// rejectEventDriven
42 None.gif
43None.gif//
44None.gif
45None.gifthis.rejectEventDriven.Activities.Add(this .rejectEvent);
46 None.gif
47None.gifthis.rejectEventDriven.ID = "rejectEventDriven" ;
48 None.gif
49None.gif//
50 None.gif
51None.gif// rejectEvent
52 None.gif
53None.gif//
54None.gif
55None.gifthis.rejectEvent.EventName = "ExpenseReportRejected" ;
56 None.gif
57None.gifthis.rejectEvent.ID = "rejectEvent" ;
58 None.gif
59None.gifthis.rejectEvent.InterfaceType = typeof (Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
60 None.gif
61None.gifthis.rejectEvent.Roles = null ;
62 None.gif
63None.gifthis.rejectEvent.Invoked += new System.EventHandler(this .rejectEvent_Invoked);
64 None.gif
65None.gif

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

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


完成顺序工作流

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

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

创建宿主程序

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
英文版 Windows Workflow Foundation (WF) is a revolutionary part of the .NET 4 Framework that allows you to orchestrate human and system interactions as a series of workflows that can be easily mapped, analyzed, adjusted, and implemented. As business problems become more complex, the need for workflow-based solutions has never been more evident. WF provides a simple and consistent way to model and implement complex problems. As a developer, you focus on developing the business logic for individual workflow tasks. The runtime handles the execution of those tasks after they have been composed into a workflow. Pro WF: Windows Workflow in .NET 4 provides you with the skills you need to incorporate WF in your applications, using a lively tutorial style with each example illustrated in C#. This book gets you up to speed with WF 4 quickly and comprehensively. Learn about WF 4s new designer, its updated programming paradigm, and the completely new set of activities that can enable and extend your workflows. This book also includes detailed coverage of how to customize your workflows and access them in a variety of ways and situations so you can maximize the advantages of this technology. What youll learn * WF 4 basics * New activities and changes to existing activities in WF 4 * Customizing your workflows * Accessing your workflows in a variety of ways in a variety of situations * Using WF with Web Services and ASP.NET * Integrating WCF and WF Who this book is for This book is for intermediate to advanced .NET developers who need to learn how to use the latest version of Windows Workflow Foundation (WF 4). This book is not a primer on .NET or the C# language. To get the most out of the examples presented in this book, it is necessary to have a good working knowledge of .NET 2.0 or higher. All of the examples are presented in C#. Table of Contents * A Quick Tour of Windows Workflow Foundation * Foundation Overview * Activities * Workflow Hosting * Procedural Flow Control * Collection-Related Activities * Flowchart Modeling Style * Host Communication * Workflow Services * Workflow Services Advanced Topics * Workflow Persistence * Customizing Workflow Persistence * Transactions, Compensation, and Exception Handling * Workflow Tracking * Enhancing the Design Experience * Advanced Custom Activities * Hosting the Workflow Designer * WF 3.x Interop and Migration

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值