您的位置:首页 > 移动开发 > Objective-C

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

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


顺序工作流(sequentialworkflow)是为执行一种由一系列预定义的步骤组成的任务而设计的。这种体系结构是模拟基于过程的应用程序的。这一节将用几个步骤来编写一个简单的开支报告程序,这个小程序使用WinFrom做界面,用顺序工作流做业务逻辑。
这个小程序有一个TextBox来输入开支报告的总数,一个Button点击提交报告。工作流将评估开支,如果开支小于1000则提请领班审批,如果大于等于1000则提请经理审批。之后,工作流会发送一个审批意见,此时,出现一个Label显示审批意见,两个Button分别表示通过和拒绝审批。当某一个按钮被点击的时候,应用程序会通知回应工作流,工作流继续处理发生的事件。

开始构造顺序工作流

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

1

using System;
2

using System.Workflow.Activities;
3

using System.Workflow.Activities.Rules;
4


5

namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
6





{
7

[RuleConditionsAttribute(typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.ExpenseReportWorkflow))]
8

public sealed partial class ExpenseReportWorkflow : System.Workflow.Activities.SequentialWorkflow
9





{
10

public ExpenseReportWorkflow()
11





{
12


13

}
14

}
15

}
16


声明工作流参数

在一个工作流运行时,它可以从宿主应用程序中接收参数。参数是ParameterDeclaration类型的对象,一旦工作流初始化完成,参数的值就能通过工作流的Parameters集合来访问。
这里的开始报告程序用了两个参数。第一个参数是开支的总数;第二个是一个传出参数,用来放置审批意见。
定义一个新的方法InitializeComponent,并在构造ExpenseRoportWorkflow类的构造函数中调用它。一下的例子示范了怎样定义两个参数并把它们加到Parameters集合中。





1

public ExpenseReportWorkflow()
2


3





{
4


5

InitializeComponent();
6


7

}
8


9


10


11

private void InitializeComponent()
12


13





{
14


15

System.Workflow.ComponentModel.ParameterDeclaration Amount = new System.Workflow.ComponentModel.ParameterDeclaration();
16


17

System.Workflow.ComponentModel.ParameterDeclaration Result = new System.Workflow.ComponentModel.ParameterDeclaration();
18


19

//
20


21

// Workflow Parameters
22


23

//
24


25

Amount.Direction = System.Workflow.ComponentModel.ParameterDirection.In;
26


27

Amount.Name = "Amount";
28


29

Amount.Type = typeof(int);
30


31

Amount.Value = null;
32


33

Result.Direction = System.Workflow.ComponentModel.ParameterDirection.Out;
34


35

Result.Name = "Result";
36


37

Result.Type = typeof(string);
38


39

Result.Value = null;
40


41

this.Parameters.Add(Amount);
42


43

this.Parameters.Add(Result);
44


45

}
46


47


使用IfElse活动

IfElse活动用条件表达式来控制工作流中流程的运行。工作流将根据条件表达式的结果来决定执行条件分支(IfElseBranch)中的哪一个活动。
例子中将使用IfElse活动。通过判断从宿主应用程序中传入的Amount参数的值是否小于1000,来决定是否将审报发送到领班,否则发送到经理。

创建IfElse活动
1.定义4个私有变量
[align=left]类型[/align]
[align=left]名称[/align]
[align=left]IfElse[/align]
[align=left]evaluateExpenseReportAmount[/align]
[align=left]IfElseBranch[/align]
[align=left]ifNeedsLeadApproval[/align]
[align=left]IfElseBranch[/align]
[align=left]elseNeedsManagerApproval[/align]
[align=left]CodeCondition[/align]
[align=left]ifElseLogicStatement[/align]
2.在InitializeComponent中用默认构造函数实例以上4个对象。
以下的代码示例了怎样创建IfElse活动,并用IfElseBranch活动联系两个逻辑分支。你需要把以下代码放到InitializeComponent方法底部。

1

//
2


3

// EvaluateExpenseReportAmount
4


5

//
6


7

this.EvaluateExpenseReportAmount.Activities.Add(this.ifNeedsLeadApproval);
8


9

this.EvaluateExpenseReportAmount.Activities.Add(this.elseNeedsManagerApproval);
10


11

this.EvaluateExpenseReportAmount.ID = "EvaluateExpenseReportAmount";
12


13

//
14


15

// ifNeedsLeadApproval
16


17

//
18


19

this.ifNeedsLeadApproval.Activities.Add(this.invokeGetLeadApproval);
20


21

ifElseLogicStatement.Condition += new System.Workflow.Activities.ConditionalExpression(this.DetermineApprovalContact);
22


23

this.ifNeedsLeadApproval.Condition = ifElseLogicStatement;
24


25

this.ifNeedsLeadApproval.ID = "ifNeedsLeadApproval";
26


27

//
28


29

// elseNeedsManagerApproval
30


31

//
32


33

this.elseNeedsManagerApproval.Activities.Add(this.invokeGetManagerApproval);
34


35

this.elseNeedsManagerApproval.Condition = null;
36


37

this.elseNeedsManagerApproval.ID = "elseNeedsManagerApproval";
38


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

1

private bool DetermineApprovalContact(object sender, EventArgs e)
2


3





{
4


5

if ( Convert.ToInt32(this.Parameters["Amount"].Value) < 1000 )
6


7

return true;
8


9


10


11

return false;
12


13

}
14


构造IfElse分支(IfElseBranch)活动

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

构建IfElseBranch活动
1. 在类中定义两个私有字段
[align=left]类型[/align]
[align=left]名称[/align]
[align=left]InvokeMethodActivity[/align]
[align=left]invokeGetLeadApproval[/align]
[align=left]InvokeMethodActivity[/align]
[align=left]invokeGetManagerApproval[/align]
2. 在InitializeComponent中用默认构造函数实例化这两个对象
以下的代码示例了怎样在父活动(IfElse)中创建IfElseBranch活动,并把两个的InvokeMethodActivity联系到对应的IfElseBranch活动上,每个InvokeMethodActivity将调用定义在IExpenseReportService接口中的方法,接口会在稍微实现。你需要把以下代码放到InitializeComponent方法底部。

1

//
2


3

// invokeGetLeadApproval
4


5

//
6


7

this.invokeGetLeadApproval.ID = "invokeGetLeadApproval";
8


9

this.invokeGetLeadApproval.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
10


11

this.invokeGetLeadApproval.MethodName = "GetLeadApproval";
12


13

//
14


15

// invokeGetManagerApproval
16


17

//
18


19

this.invokeGetManagerApproval.ID = "invokeGetManagerApproval";
20


21

this.invokeGetManagerApproval.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
22


23

this.invokeGetManagerApproval.MethodName = "GetManagerApproval";
24


25


以下代码定义了IExpenseReportService接口

1

using System;
2


3

using System.Workflow.ComponentModel;
4


5

using System.Workflow.Runtime.Messaging;
6


7


8


9

namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow
10


11





{
12


13

[DataExchangeService]
14


15

public interface IExpenseReportService
16


17





{
18


19

void GetLeadApproval();
20


21

void GetManagerApproval();
22


23

event EventHandler<WorkflowMessageEventArgs> ExpenseReportApproved;
24


25

event EventHandler<WorkflowMessageEventArgs> ExpenseReportRejected;
26


27

}
28


29

}
30


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个私有字段
[align=left]类型[/align]
[align=left]名称[/align]
[align=left]Listen[/align]
[align=left]listenApproveReject[/align]
[align=left]EventDriven[/align]
[align=left]approveEventDriven[/align]
[align=left]EventDriven[/align]
[align=left]rejectEventDriven[/align]
[align=left]EventSinkActivity[/align]
[align=left]approveEvent[/align]
[align=left]EventSinkActivity[/align]
[align=left]rejectEvent[/align]
2. 在InitializeComponent中实例化。
以下的代码示例了怎样在创建Listen活动和EventSinkActivity活动,来监听宿主程序发出的事件。你需要把以下代码放到InitializeComponent方法底部。
使用EventSinkActivity时,为了在工作流中加入一些附加逻辑,你可以为Invoked事件创建一个事件处理程序。一下是事件处理程序的代码。
1

//
2


3

// listenApproveReject
4


5

//
6


7

this.listenApproveReject.Activities.Add(this.approveEventDriven);
8


9

this.listenApproveReject.Activities.Add(this.rejectEventDriven);
10


11

this.listenApproveReject.ID = "listenApproveReject";
12


13

//
14


15

// approveEventDriven
16


17

//
18


19

this.approveEventDriven.Activities.Add(this.approveEvent);
20


21

this.approveEventDriven.ID = "approveEventDriven";
22


23

//
24


25

// approveEvent
26


27

//
28


29

this.approveEvent.EventName = "ExpenseReportApproved";
30


31

this.approveEvent.ID = "approveEvent";
32


33

this.approveEvent.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
34


35

this.approveEvent.Roles = null;
36


37

this.approveEvent.Invoked += new System.EventHandler(this.approveEvent_Invoked);
38


39

//
40


41

// rejectEventDriven
42


43

//
44


45

this.rejectEventDriven.Activities.Add(this.rejectEvent);
46


47

this.rejectEventDriven.ID = "rejectEventDriven";
48


49

//
50


51

// rejectEvent
52


53

//
54


55

this.rejectEvent.EventName = "ExpenseReportRejected";
56


57

this.rejectEvent.ID = "rejectEvent";
58


59

this.rejectEvent.InterfaceType = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService);
60


61

this.rejectEvent.Roles = null;
62


63

this.rejectEvent.Invoked += new System.EventHandler(this.rejectEvent_Invoked);
64


65


完成顺序工作流
1

private void approveEvent_Invoked(object sender, EventArgs e)
2


3





{
4


5

this.Parameters["Result"].Value = "Report Approved";
6


7

}
8


9


10


11

private void rejectEvent_Invoked(object sender, EventArgs e)
12


13





{
14


15

this.Parameters["Result"].Value = "Report Rejected";
16


17

}
18


19


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

1

//
2


3

// ExpenseReportWorkflow
4


5

//
6


7

this.Activities.Add(this.EvaluateExpenseReportAmount);
8


9

this.Activities.Add(this.listenApproveReject);
10


11

this.DynamicUpdateCondition = null;
12


13

this.ID = "ExpenseReportWorkflow";
14


15


创建宿主程序

WWF需要一个宿主程序来运行工作流。当程序开始运行,WWF运行时引擎也随之启动。而之前构造好的工作流,则到用户点击了Submit按钮后才真正启动。
建立一个新的源文件,取名Program。以下的代码包含了完整的WinForm应用程序。IExpenseReportService接口GetLeadApproval和GetmanagerApproval方法已经定义在另一个文件中。宿主程序实现了这个接口。在approval和rejected按钮的click事件中,将引发ExpenseReprotApproval或ExpenseReprotRejected事件。

1

using System;
2


3

using System.ComponentModel;
4


5

using System.Drawing;
6


7

using System.Windows.Forms;
8


9

using System.Collections.Generic;
10


11

using System.Workflow.Runtime;
12


13

using System.Workflow.Runtime.Hosting;
14


15

using System.Workflow.Runtime.Messaging;
16


17


18


19

namespace Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflowHost
20


21





{
22


23

public class MainForm : Form, Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService
24


25





{
26


27

private System.Windows.Forms.Label label1;
28


29

private System.Windows.Forms.TextBox result;
30


31

private System.Windows.Forms.Label label2;
32


33

private System.Windows.Forms.Button submitButton;
34


35

private System.Windows.Forms.Label approvalState;
36


37

private System.Windows.Forms.Button approveButton;
38


39

private System.Windows.Forms.Button rejectButton;
40


41

private System.Windows.Forms.TextBox amount;
42


43

private System.Windows.Forms.Panel panel1;
44


45


46


47

private System.ComponentModel.IContainer components = null;
48


49


50


51

private delegate void GetApprovalDelegate();
52


53

private WorkflowRuntime workflowRuntime = null;
54


55

private WorkflowInstance workflowInstance = null;
56


57


58


59

public MainForm()
60


61





{
62


63

InitializeComponent();
64


65


66


67

// Collapse approve/reject panel
68


69

this.Height -= this.panel1.Height;
70


71


72


73

workflowRuntime = new WorkflowRuntime();
74


75

workflowRuntime.AddService(this);
76


77

workflowRuntime.StartRuntime();
78


79


80


81

workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted);
82


83

}
84


85


86


87

protected override void Dispose(bool disposing)
88


89





{
90


91

if (disposing && (components != null))
92


93





{
94


95

components.Dispose();
96


97

}
98


99

base.Dispose(disposing);
100


101

}
102


103


104


105

private void InitializeComponent()
106


107





{
108


109

this.label1 = new System.Windows.Forms.Label();
110


111

this.result = new System.Windows.Forms.TextBox();
112


113

this.label2 = new System.Windows.Forms.Label();
114


115

this.submitButton = new System.Windows.Forms.Button();
116


117

this.approvalState = new System.Windows.Forms.Label();
118


119

this.approveButton = new System.Windows.Forms.Button();
120


121

this.rejectButton = new System.Windows.Forms.Button();
122


123

this.amount = new System.Windows.Forms.TextBox();
124


125

this.panel1 = new System.Windows.Forms.Panel();
126


127

this.panel1.SuspendLayout();
128


129

this.SuspendLayout();
130


131

//
132


133

// label1
134


135

//
136


137

this.label1.AutoSize = true;
138


139

this.label1.Location = new System.Drawing.Point(13, 13);
140


141

this.label1.Name = "label1";
142


143

this.label1.Size = new System.Drawing.Size(39, 13);
144


145

this.label1.TabIndex = 1;
146


147

this.label1.Text = "Amount";
148


149

//
150


151

// result
152


153

//
154


155

this.result.Location = new System.Drawing.Point(13, 69);
156


157

this.result.Name = "result";
158


159

this.result.ReadOnly = true;
160


161

this.result.Size = new System.Drawing.Size(162, 20);
162


163

this.result.TabIndex = 1;
164


165

this.result.TabStop = false;
166


167

//
168


169

// label2
170


171

//
172


173

this.label2.AutoSize = true;
174


175

this.label2.Location = new System.Drawing.Point(13, 54);
176


177

this.label2.Name = "label2";
178


179

this.label2.Size = new System.Drawing.Size(33, 13);
180


181

this.label2.TabIndex = 3;
182


183

this.label2.Text = "Result";
184


185

//
186


187

// submitButton
188


189

//
190


191

this.submitButton.Enabled = false;
192


193

this.submitButton.Location = new System.Drawing.Point(56, 95);
194


195

this.submitButton.Name = "submitButton";
196


197

this.submitButton.Size = new System.Drawing.Size(75, 23);
198


199

this.submitButton.TabIndex = 2;
200


201

this.submitButton.Text = "Submit";
202


203

this.submitButton.Click += new System.EventHandler(this.submitButton_Click);
204


205

//
206


207

// approvalState
208


209

//
210


211

this.approvalState.AutoSize = true;
212


213

this.approvalState.Location = new System.Drawing.Point(10, 9);
214


215

this.approvalState.Name = "approvalState";
216


217

this.approvalState.Size = new System.Drawing.Size(45, 13);
218


219

this.approvalState.TabIndex = 4;
220


221

this.approvalState.Text = "Approval";
222


223

//
224


225

// approveButton
226


227

//
228


229

this.approveButton.Enabled = false;
230


231

this.approveButton.Location = new System.Drawing.Point(11, 25);
232


233

this.approveButton.Name = "approveButton";
234


235

this.approveButton.Size = new System.Drawing.Size(75, 23);
236


237

this.approveButton.TabIndex = 0;
238


239

this.approveButton.Text = "Approve";
240


241

this.approveButton.Click += new System.EventHandler(this.approveButton_Click);
242


243

//
244


245

// rejectButton
246


247

//
248


249

this.rejectButton.Enabled = false;
250


251

this.rejectButton.Location = new System.Drawing.Point(86, 25);
252


253

this.rejectButton.Name = "rejectButton";
254


255

this.rejectButton.Size = new System.Drawing.Size(75, 23);
256


257

this.rejectButton.TabIndex = 1;
258


259

this.rejectButton.Text = "Reject";
260


261

this.rejectButton.Click += new System.EventHandler(this.rejectButton_Click);
262


263

//
264


265

// amount
266


267

//
268


269

this.amount.Location = new System.Drawing.Point(13, 29);
270


271

this.amount.MaxLength = 9;
272


273

this.amount.Name = "amount";
274


275

this.amount.Size = new System.Drawing.Size(162, 20);
276


277

this.amount.TabIndex = 0;
278


279

this.amount.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.amount_KeyPress);
280


281

this.amount.TextChanged += new System.EventHandler(this.amount_TextChanged);
282


283

//
284


285

// panel1
286


287

//
288


289

this.panel1.Controls.Add(this.approvalState);
290


291

this.panel1.Controls.Add(this.approveButton);
292


293

this.panel1.Controls.Add(this.rejectButton);
294


295

this.panel1.Location = new System.Drawing.Point(3, 124);
296


297

this.panel1.Name = "panel1";
298


299

this.panel1.Size = new System.Drawing.Size(172, 66);
300


301

this.panel1.TabIndex = 8;
302


303

//
304


305

// MainForm
306


307

//
308


309

this.AcceptButton = this.submitButton;
310


311

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
312


313

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
314


315

this.ClientSize = new System.Drawing.Size(187, 201);
316


317

this.Controls.Add(this.panel1);
318


319

this.Controls.Add(this.amount);
320


321

this.Controls.Add(this.submitButton);
322


323

this.Controls.Add(this.label2);
324


325

this.Controls.Add(this.result);
326


327

this.Controls.Add(this.label1);
328


329

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
330


331

this.MaximizeBox = false;
332


333

this.MinimizeBox = false;
334


335

this.Name = "MainForm";
336


337

this.Text = "Simple Expense Report";
338


339

this.panel1.ResumeLayout(false);
340


341

this.panel1.PerformLayout();
342


343

this.ResumeLayout(false);
344


345

this.PerformLayout();
346


347


348


349

}
350


351


352


353

private void submitButton_Click(object sender, EventArgs e)
354


355





{
356


357

Type type = typeof(Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.ExpenseReportWorkflow);
358


359


360


361

// Construct workflow parameters
362


363

Dictionary<string, object> properties = new Dictionary<string, object>();
364


365

properties.Add("Amount", Int32.Parse(this.amount.Text));
366


367

properties.Add("Result", string.Empty);
368


369


370


371

// Start the workflow
372


373

workflowInstance = workflowRuntime.StartWorkflow(type, properties);
374


375

}
376


377


378


379

void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
380


381





{
382


383

if (this.result.InvokeRequired)
384


385

this.result.Invoke(new EventHandler<WorkflowCompletedEventArgs>(this.workflowRuntime_WorkflowCompleted), sender, e);
386


387

else
388


389





{
390


391

this.result.Text = e.OutputParameters["Result"].ToString();
392


393


394


395

// Clear fields
396


397

this.amount.Text = string.Empty;
398


399


400


401

// Disable buttons
402


403

this.approveButton.Enabled = false;
404


405

this.rejectButton.Enabled = false;
406


407

}
408


409

}
410


411


412


413

private void approveButton_Click(object sender, EventArgs e)
414


415





{
416


417

// Raise the ExpenseReportApproved event back to the workflow
418


419

ExpenseReportApproved(null, new WorkflowMessageEventArgs(this.workflowInstance.InstanceId));
420


421

this.Height -= this.panel1.Height;
422


423

this.submitButton.Enabled = true;
424


425

}
426


427


428


429

private void rejectButton_Click(object sender, EventArgs e)
430


431





{
432


433

// Raise the ExpenseReportRejected event back to the workflow
434


435

ExpenseReportRejected(null, new WorkflowMessageEventArgs(this.workflowInstance.InstanceId));
436


437

this.Height -= this.panel1.Height;
438


439

this.submitButton.Enabled = true;
440


441

}
442


443


444


445



IExpenseReportService Members#region IExpenseReportService Members
446


447


448


449

public void GetLeadApproval()
450


451





{
452


453

if (this.approvalState.InvokeRequired)
454


455

this.approvalState.Invoke(new GetApprovalDelegate(this.GetLeadApproval));
456


457

else
458


459





{
460


461

this.approvalState.Text = "Lead approval needed";
462


463

this.approveButton.Enabled = true;
464


465

this.rejectButton.Enabled = true;
466


467


468


469

// expand the panel
470


471

this.Height += this.panel1.Height;
472


473

this.submitButton.Enabled = false;
474


475

}
476


477

}
478


479


480


481

public void GetManagerApproval()
482


483





{
484


485

if (this.approvalState.InvokeRequired)
486


487

this.approvalState.Invoke(new GetApprovalDelegate(this.GetManagerApproval));
488


489

else
490


491





{
492


493

this.approvalState.Text = "Manager approval needed";
494


495

this.approveButton.Enabled = true;
496


497

this.rejectButton.Enabled = true;
498


499


500


501

// expand the panel
502


503

this.Height += this.panel1.Height;
504


505

this.submitButton.Enabled = false;
506


507

}
508


509

}
510


511


512


513

public event EventHandler<WorkflowMessageEventArgs> ExpenseReportApproved;
514


515

public event EventHandler<WorkflowMessageEventArgs> ExpenseReportRejected;
516


517


518


519

#endregion
520


521


522


523

private void amount_KeyPress(object sender, KeyPressEventArgs e)
524


525





{
526


527

if (!Char.IsControl(e.KeyChar) && (!Char.IsDigit(e.KeyChar)))
528


529

e.KeyChar = Char.MinValue;
530


531

}
532


533


534


535

private void amount_TextChanged(object sender, EventArgs e)
536


537





{
538


539

submitButton.Enabled = amount.Text.Length > 0;
540


541

}
542


543

}
544


545


546


547

static class Program
548


549





{
550


551



/**//// <summary>
552


553

/// The main entry point for the application.
554


555

/// </summary>
556


557

[STAThread]
558


559

static void Main()
560


561





{
562


563

Application.EnableVisualStyles();
564


565

Application.Run(new MainForm());
566


567

}
568


569

}
570


571

}
572


573


Ps:上面还有个问题没有解释清楚,我reflect了一下,看了源码才知道个大概。
那就是IfElseBranch中的InvokeMethodActivity。
InvokeMethodActivity中有一个Type类型的InterfaceType属性,使用时,需要设置这个属性,并把MethodName设为这个接口中的一个方法的名称。运行时,工作流引擎(也就是WorkflowRuntime)将通过反射调用这个接口。
但引擎怎么知道调用接口的哪个实现呢?你看
workflowRuntime = new WorkflowRuntime();
workflowRuntime.AddService(this);
workflowRuntime.StartRuntime();
原来,初始化引擎时,我们已经把实现了这个interface的类型的实例(this)注册到工作流中了。运行时,引擎就遍历所有已经注册的服务,如果实现了这个接口,这调用它。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐