Windows Workflow Foundation(一)(转载)

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

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

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

工作流模型

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

组件的重用

  WWF为开发者提供了一系列的活动——活动是一种包含了工作单元的可配置逻辑结构。这种结构封装了开发者可能经常性用到的一些部件,这样就节省了开发者的时间。
  如果遇到一些特殊的需求或场景,WWF同样为开发自定义的活动提供了简单的方法。
  通过将工作流引擎载入进程,WWF可以使任何应用程序和服务容器运行工作流。
  运行时服务组件被设计成可插件形式的,这个可使应用程序以最合适的方式来提供它们的服务。WWF还提供了一组运行时服务的默认实现,这些服务能满足大部分类型的应用程序。
 
另外,WWF还提供了对ASP.NETout-of-the-box(啥意思?)支持,让构造和运行能在IISASP.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.gif    public sealed partial class
 ExpenseReportWorkflow : System.Workflow.Activities.SequentialWorkflow
 9ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif
{
10InBlock.gif        public
 ExpenseReportWorkflow()
11ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
12
InBlock.gif
13ExpandedSubBlockEnd.gif        }

14ExpandedSubBlockEnd.gif    }

15ExpandedBlockEnd.gif}

16None.gif

声明工作流参数

 

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

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

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

ContractedBlock.gifExpandedBlockStart.gif
 1None.gifpublic ExpenseReportWorkflow()
 2
None.gif
 3ExpandedBlockStart.gifContractedBlock.gifdot.gif
{
 4
InBlock.gif
 5
InBlock.gif    InitializeComponent();
 6
InBlock.gif
 7ExpandedBlockEnd.gif}

 8None.gif
 9
None.gif 
10
None.gif
11None.gifprivate void
 InitializeComponent()
12
None.gif
13ExpandedBlockStart.gifContractedBlock.gifdot.gif
{
14
InBlock.gif
15InBlock.gif    System.Workflow.ComponentModel.ParameterDeclaration Amount = new
 System.Workflow.ComponentModel.ParameterDeclaration();
16
InBlock.gif
17InBlock.gif    System.Workflow.ComponentModel.ParameterDeclaration Result = new
 System.Workflow.ComponentModel.ParameterDeclaration();
18
InBlock.gif
19InBlock.gif    //

20InBlock.gif
21InBlock.gif    //
 Workflow Parameters
22
InBlock.gif
23InBlock.gif    
//
24InBlock.gif

25InBlock.gif    Amount.Direction = System.Workflow.ComponentModel.ParameterDirection.In;
26
InBlock.gif
27InBlock.gif    Amount.Name = "Amount"
;
28
InBlock.gif
29InBlock.gif    Amount.Type = typeof(int
);
30
InBlock.gif
31InBlock.gif    Amount.Value = null
;
32
InBlock.gif
33InBlock.gif    Result.Direction =
 System.Workflow.ComponentModel.ParameterDirection.Out;
34
InBlock.gif
35InBlock.gif    Result.Name = "Result"
;
36
InBlock.gif
37InBlock.gif    Result.Type = typeof(string
);
38
InBlock.gif
39InBlock.gif    Result.Value = null
;
40
InBlock.gif
41InBlock.gif    this
.Parameters.Add(Amount);
42
InBlock.gif
43InBlock.gif    this
.Parameters.Add(Result);
44
InBlock.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

 WWFIfElse活动中,有两种评估条件表达式的方式。一种是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.gif    if ( Convert.ToInt32(this.Parameters["Amount"].Value) < 1000
 )
 6
InBlock.gif
 7InBlock.gif        return true
;
 8
InBlock.gif
 9
InBlock.gif 
10
InBlock.gif
11InBlock.gif    return 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.gif    public interface
 IExpenseReportService
16
InBlock.gif
17ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif
{
18
InBlock.gif
19InBlock.gif        void
 GetLeadApproval();
20
InBlock.gif
21InBlock.gif        void
 GetManagerApproval();
22
InBlock.gif
23InBlock.gif        event EventHandler<WorkflowMessageEventArgs>
 ExpenseReportApproved;
24
InBlock.gif
25InBlock.gif        event EventHandler<WorkflowMessageEventArgs>
 ExpenseReportRejected;
26
InBlock.gif
27ExpandedSubBlockEnd.gif    }

28InBlock.gif
29ExpandedBlockEnd.gif}

30 None.gif
31None.gif

监听宿主事件

 

在这个阶段,工作流已经从宿主程序接受了两个参数(译者注:其中一个为out参数,此时设为null),评估了Amount参数,作出了到底该提请谁确认审批的决定,并通知了宿主程序在继续接下来的处理之前,确认审批。这里,Listen活动和EventSinkActivity活动往往配合使用,来监听宿主程序触发指定的事件。接着,一个approvalrejection事件被引发,工作流继续执行,返回审批结果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.gif    this.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.gif    this.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接口GetLeadApprovalGetmanagerApproval方法已经定义在另一个文件中。宿主程序实现了这个接口。在approvalrejected按钮的click事件中,将引发ExpenseReprotApprovalExpenseReprotRejected事件。

  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.gif    public class
 MainForm : Form, Microsoft.Samples.Workflow.Quickstarts.SequentialWorkflow.IExpenseReportService
 24
InBlock.gif
 25ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif
{
 26
InBlock.gif
 27InBlock.gif        private
 System.Windows.Forms.Label label1;
 28
InBlock.gif
 29InBlock.gif        private
 System.Windows.Forms.TextBox result;
 30
InBlock.gif
 31InBlock.gif        private
 System.Windows.Forms.Label label2;
 32
InBlock.gif
 33InBlock.gif        private
 System.Windows.Forms.Button submitButton;
 34
InBlock.gif
 35InBlock.gif        private
 System.Windows.Forms.Label approvalState;
 36
InBlock.gif
 37InBlock.gif        private
 System.Windows.Forms.Button approveButton;
 38
InBlock.gif
 39InBlock.gif        private
 System.Windows.Forms.Button rejectButton;
 40
InBlock.gif
 41InBlock.gif        private
 System.Windows.Forms.TextBox amount;
 42
InBlock.gif
 43InBlock.gif        private
 System.Windows.Forms.Panel panel1;
 44
InBlock.gif
 45
InBlock.gif 
 46
InBlock.gif
 47InBlock.gif        private System.ComponentModel.IContainer components = null
;
 48
InBlock.gif
 49
InBlock.gif 
 50
InBlock.gif
 51InBlock.gif        private delegate void
 GetApprovalDelegate();
 52
InBlock.gif
 53InBlock.gif        private WorkflowRuntime workflowRuntime = null
;
 54
InBlock.gif
 55InBlock.gif        private WorkflowInstance workflowInstance = null
;
 56
InBlock.gif
 57
InBlock.gif 
 58
InBlock.gif
 59InBlock.gif        public
 MainForm()
 60
InBlock.gif
 61ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.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.gif            this.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        }

 84InBlock.gif
 85
InBlock.gif 
 86
InBlock.gif
 87InBlock.gif        protected override void Dispose(bool
 disposing)
 88
InBlock.gif
 89ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
 90
InBlock.gif
 91InBlock.gif            if (disposing && (components != null
))
 92
InBlock.gif
 93ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif
{
 94
InBlock.gif
 95
InBlock.gif                components.Dispose();
 96
InBlock.gif
 97ExpandedSubBlockEnd.gif            }

 98InBlock.gif
 99InBlock.gif            base
.Dispose(disposing);
100
InBlock.gif
101ExpandedSubBlockEnd.gif        }

102InBlock.gif
103
InBlock.gif 
104
InBlock.gif
105InBlock.gif        private void
 InitializeComponent()
106
InBlock.gif
107ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
108
InBlock.gif
109InBlock.gif            this.label1 = new
 System.Windows.Forms.Label();
110
InBlock.gif
111InBlock.gif            this.result = new
 System.Windows.Forms.TextBox();
112
InBlock.gif
113InBlock.gif            this.label2 = new
 System.Windows.Forms.Label();
114
InBlock.gif
115InBlock.gif            this.submitButton = new
 System.Windows.Forms.Button();
116
InBlock.gif
117InBlock.gif            this.approvalState = new
 System.Windows.Forms.Label();
118
InBlock.gif
119InBlock.gif            this.approveButton = new
 System.Windows.Forms.Button();
120
InBlock.gif
121InBlock.gif            this.rejectButton = new
 System.Windows.Forms.Button();
122
InBlock.gif
123InBlock.gif            this.amount = new
 System.Windows.Forms.TextBox();
124
InBlock.gif
125InBlock.gif            this.panel1 = new
 System.Windows.Forms.Panel();
126
InBlock.gif
127InBlock.gif            this
.panel1.SuspendLayout();
128
InBlock.gif
129InBlock.gif            this
.SuspendLayout();
130
InBlock.gif
131InBlock.gif            //
 
132
InBlock.gif
133InBlock.gif            //
 label1
134
InBlock.gif
135InBlock.gif            // 

136InBlock.gif
137InBlock.gif            this.label1.AutoSize = true;
138
InBlock.gif
139InBlock.gif            this.label1.Location = new System.Drawing.Point(1313
);
140
InBlock.gif
141InBlock.gif            this.label1.Name = "label1"
;
142
InBlock.gif
143InBlock.gif            this.label1.Size = new System.Drawing.Size(3913
);
144
InBlock.gif
145InBlock.gif            this.label1.TabIndex = 1
;
146
InBlock.gif
147InBlock.gif            this.label1.Text = "Amount"
;
148
InBlock.gif
149InBlock.gif            //
 
150
InBlock.gif
151InBlock.gif            //
 result
152
InBlock.gif
153InBlock.gif            // 

154InBlock.gif
155InBlock.gif            this.result.Location = new System.Drawing.Point(1369);
156
InBlock.gif
157InBlock.gif            this.result.Name = "result"
;
158
InBlock.gif
159InBlock.gif            this.result.ReadOnly = true
;
160
InBlock.gif
161InBlock.gif            this.result.Size = new System.Drawing.Size(16220
);
162
InBlock.gif
163InBlock.gif            this.result.TabIndex = 1
;
164
InBlock.gif
165InBlock.gif            this.result.TabStop = false
;
166
InBlock.gif
167InBlock.gif            //
 
168
InBlock.gif
169InBlock.gif            //
 label2
170
InBlock.gif
171InBlock.gif            // 

172InBlock.gif
173InBlock.gif            this.label2.AutoSize = true;
174
InBlock.gif
175InBlock.gif            this.label2.Location = new System.Drawing.Point(1354
);
176
InBlock.gif
177InBlock.gif            this.label2.Name = "label2"
;
178
InBlock.gif
179InBlock.gif            this.label2.Size = new System.Drawing.Size(3313
);
180
InBlock.gif
181InBlock.gif            this.label2.TabIndex = 3
;
182
InBlock.gif
183InBlock.gif            this.label2.Text = "Result"
;
184
InBlock.gif
185InBlock.gif            //
 
186
InBlock.gif
187InBlock.gif            //
 submitButton
188
InBlock.gif
189InBlock.gif            // 

190InBlock.gif
191InBlock.gif            this.submitButton.Enabled = false;
192
InBlock.gif
193InBlock.gif            this.submitButton.Location = new System.Drawing.Point(5695
);
194
InBlock.gif
195InBlock.gif            this.submitButton.Name = "submitButton"
;
196
InBlock.gif
197InBlock.gif            this.submitButton.Size = new System.Drawing.Size(7523
);
198
InBlock.gif
199InBlock.gif            this.submitButton.TabIndex = 2
;
200
InBlock.gif
201InBlock.gif            this.submitButton.Text = "Submit"
;
202
InBlock.gif
203InBlock.gif            this.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.gif            this.approvalState.AutoSize = true;
212
InBlock.gif
213InBlock.gif            this.approvalState.Location = new System.Drawing.Point(109
);
214
InBlock.gif
215InBlock.gif            this.approvalState.Name = "approvalState"
;
216
InBlock.gif
217InBlock.gif            this.approvalState.Size = new System.Drawing.Size(4513
);
218
InBlock.gif
219InBlock.gif            this.approvalState.TabIndex = 4
;
220
InBlock.gif
221InBlock.gif            this.approvalState.Text = "Approval"
;
222
InBlock.gif
223InBlock.gif            //
 
224
InBlock.gif
225InBlock.gif            //
 approveButton
226
InBlock.gif
227InBlock.gif            // 

228InBlock.gif
229InBlock.gif            this.approveButton.Enabled = false;
230
InBlock.gif
231InBlock.gif            this.approveButton.Location = new System.Drawing.Point(1125
);
232
InBlock.gif
233InBlock.gif            this.approveButton.Name = "approveButton"
;
234
InBlock.gif
235InBlock.gif            this.approveButton.Size = new System.Drawing.Size(7523
);
236
InBlock.gif
237InBlock.gif            this.approveButton.TabIndex = 0
;
238
InBlock.gif
239InBlock.gif            this.approveButton.Text = "Approve"
;
240
InBlock.gif
241InBlock.gif            this.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.gif            this.rejectButton.Enabled = false;
250
InBlock.gif
251InBlock.gif            this.rejectButton.Location = new System.Drawing.Point(8625
);
252
InBlock.gif
253InBlock.gif            this.rejectButton.Name = "rejectButton"
;
254
InBlock.gif
255InBlock.gif            this.rejectButton.Size = new System.Drawing.Size(7523
);
256
InBlock.gif
257InBlock.gif            this.rejectButton.TabIndex = 1
;
258
InBlock.gif
259InBlock.gif            this.rejectButton.Text = "Reject"
;
260
InBlock.gif
261InBlock.gif            this.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.gif            this.amount.Location = new System.Drawing.Point(1329);
270
InBlock.gif
271InBlock.gif            this.amount.MaxLength = 9
;
272
InBlock.gif
273InBlock.gif            this.amount.Name = "amount"
;
274
InBlock.gif
275InBlock.gif            this.amount.Size = new System.Drawing.Size(16220
);
276
InBlock.gif
277InBlock.gif            this.amount.TabIndex = 0
;
278
InBlock.gif
279InBlock.gif            this.amount.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this
.amount_KeyPress);
280
InBlock.gif
281InBlock.gif            this.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.gif            this.panel1.Controls.Add(this.approvalState);
290
InBlock.gif
291InBlock.gif            this.panel1.Controls.Add(this
.approveButton);
292
InBlock.gif
293InBlock.gif            this.panel1.Controls.Add(this
.rejectButton);
294
InBlock.gif
295InBlock.gif            this.panel1.Location = new System.Drawing.Point(3124
);
296
InBlock.gif
297InBlock.gif            this.panel1.Name = "panel1"
;
298
InBlock.gif
299InBlock.gif            this.panel1.Size = new System.Drawing.Size(17266
);
300
InBlock.gif
301InBlock.gif            this.panel1.TabIndex = 8
;
302
InBlock.gif
303InBlock.gif            //
 
304
InBlock.gif
305InBlock.gif            //
 MainForm
306
InBlock.gif
307InBlock.gif            // 

308InBlock.gif
309InBlock.gif            this.AcceptButton = this.submitButton;
310
InBlock.gif
311InBlock.gif            this.AutoScaleDimensions = new
 System.Drawing.SizeF(6F, 13F);
312
InBlock.gif
313InBlock.gif            this.AutoScaleMode =
 System.Windows.Forms.AutoScaleMode.Font;
314
InBlock.gif
315InBlock.gif            this.ClientSize = new System.Drawing.Size(187201
);
316
InBlock.gif
317InBlock.gif            this.Controls.Add(this
.panel1);
318
InBlock.gif
319InBlock.gif            this.Controls.Add(this
.amount);
320
InBlock.gif
321InBlock.gif            this.Controls.Add(this
.submitButton);
322
InBlock.gif
323InBlock.gif            this.Controls.Add(this
.label2);
324
InBlock.gif
325InBlock.gif            this.Controls.Add(this
.result);
326
InBlock.gif
327InBlock.gif            this.Controls.Add(this
.label1);
328
InBlock.gif
329InBlock.gif            this.FormBorderStyle =
 System.Windows.Forms.FormBorderStyle.Fixed3D;
330
InBlock.gif
331InBlock.gif            this.MaximizeBox = false
;
332
InBlock.gif
333InBlock.gif            this.MinimizeBox = false
;
334
InBlock.gif
335InBlock.gif            this.Name = "MainForm"
;
336
InBlock.gif
337InBlock.gif            this.Text = "Simple Expense Report"
;
338
InBlock.gif
339InBlock.gif            this.panel1.ResumeLayout(false
);
340
InBlock.gif
341InBlock.gif            this
.panel1.PerformLayout();
342
InBlock.gif
343InBlock.gif            this.ResumeLayout(false
);
344
InBlock.gif
345InBlock.gif            this
.PerformLayout();
346
InBlock.gif
347
InBlock.gif 
348
InBlock.gif
349ExpandedSubBlockEnd.gif        }

350InBlock.gif
351
InBlock.gif 
352
InBlock.gif
353InBlock.gif        private void submitButton_Click(object
 sender, EventArgs e)
354
InBlock.gif
355ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.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<stringobject> properties = new Dictionary<stringobject>();
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        }

376InBlock.gif
377
InBlock.gif 
378
InBlock.gif
379InBlock.gif        void workflowRuntime_WorkflowCompleted(object
 sender, WorkflowCompletedEventArgs e)
380
InBlock.gif
381ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
382
InBlock.gif
383InBlock.gif            if (this
.result.InvokeRequired)
384
InBlock.gif
385InBlock.gif                this.result.Invoke(new EventHandler<WorkflowCompletedEventArgs>(this
.workflowRuntime_WorkflowCompleted), sender, e);
386
InBlock.gif
387InBlock.gif            else

388InBlock.gif
389ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif
{
390
InBlock.gif
391InBlock.gif                this.result.Text = e.OutputParameters["Result"
].ToString();
392
InBlock.gif
393
InBlock.gif 
394
InBlock.gif
395InBlock.gif                // Clear fields

396InBlock.gif
397InBlock.gif                this.amount.Text = string.Empty;
398
InBlock.gif
399
InBlock.gif 
400
InBlock.gif
401InBlock.gif                // Disable buttons

402InBlock.gif
403InBlock.gif                this.approveButton.Enabled = false;
404
InBlock.gif
405InBlock.gif                this.rejectButton.Enabled = false
;
406
InBlock.gif
407ExpandedSubBlockEnd.gif            }

408InBlock.gif
409ExpandedSubBlockEnd.gif        }

410InBlock.gif
411
InBlock.gif 
412
InBlock.gif
413InBlock.gif        private void approveButton_Click(object
 sender, EventArgs e)
414
InBlock.gif
415ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
416
InBlock.gif
417InBlock.gif            // Raise the ExpenseReportApproved event back to the workflow

418InBlock.gif
419InBlock.gif            ExpenseReportApproved(nullnew WorkflowMessageEventArgs(this.workflowInstance.InstanceId));
420
InBlock.gif
421InBlock.gif            this.Height -= this
.panel1.Height;
422
InBlock.gif
423InBlock.gif            this.submitButton.Enabled = true
;
424
InBlock.gif
425ExpandedSubBlockEnd.gif        }

426InBlock.gif
427
InBlock.gif 
428
InBlock.gif
429InBlock.gif        private void rejectButton_Click(object
 sender, EventArgs e)
430
InBlock.gif
431ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
432
InBlock.gif
433InBlock.gif            // Raise the ExpenseReportRejected event back to the workflow

434InBlock.gif
435InBlock.gif            ExpenseReportRejected(nullnew WorkflowMessageEventArgs(this.workflowInstance.InstanceId));
436
InBlock.gif
437InBlock.gif            this.Height -= this
.panel1.Height;
438
InBlock.gif
439InBlock.gif            this.submitButton.Enabled = true
;
440
InBlock.gif
441ExpandedSubBlockEnd.gif        }

442InBlock.gif
443
InBlock.gif 
444
InBlock.gif
445ContractedSubBlock.gifExpandedSubBlockStart.gif        IExpenseReportService Members
#region IExpenseReportService Members
446InBlock.gif
447
InBlock.gif 
448
InBlock.gif
449InBlock.gif        public void
 GetLeadApproval()
450
InBlock.gif
451ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
452
InBlock.gif
453InBlock.gif            if (this
.approvalState.InvokeRequired)
454
InBlock.gif
455InBlock.gif                this.approvalState.Invoke(new GetApprovalDelegate(this
.GetLeadApproval));
456
InBlock.gif
457InBlock.gif            else

458InBlock.gif
459ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif
{
460
InBlock.gif
461InBlock.gif                this.approvalState.Text = "Lead approval needed"
;
462
InBlock.gif
463InBlock.gif                this.approveButton.Enabled = true
;
464
InBlock.gif
465InBlock.gif                this.rejectButton.Enabled = true
;
466
InBlock.gif
467
InBlock.gif 
468
InBlock.gif
469InBlock.gif                // expand the panel

470InBlock.gif
471InBlock.gif                this.Height += this.panel1.Height;
472
InBlock.gif
473InBlock.gif                this.submitButton.Enabled = false
;
474
InBlock.gif
475ExpandedSubBlockEnd.gif            }

476InBlock.gif
477ExpandedSubBlockEnd.gif        }

478InBlock.gif
479
InBlock.gif 
480
InBlock.gif
481InBlock.gif        public void
 GetManagerApproval()
482
InBlock.gif
483ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
484
InBlock.gif
485InBlock.gif            if (this
.approvalState.InvokeRequired)
486
InBlock.gif
487InBlock.gif                this.approvalState.Invoke(new GetApprovalDelegate(this
.GetManagerApproval));
488
InBlock.gif
489InBlock.gif            else

490InBlock.gif
491ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif
{
492
InBlock.gif
493InBlock.gif                this.approvalState.Text = "Manager approval needed"
;
494
InBlock.gif
495InBlock.gif                this.approveButton.Enabled = true
;
496
InBlock.gif
497InBlock.gif                this.rejectButton.Enabled = true
;
498
InBlock.gif
499
InBlock.gif 
500
InBlock.gif
501InBlock.gif                // expand the panel

502InBlock.gif
503InBlock.gif                this.Height += this.panel1.Height;
504
InBlock.gif
505InBlock.gif                this.submitButton.Enabled = false
;
506
InBlock.gif
507ExpandedSubBlockEnd.gif            }

508InBlock.gif
509ExpandedSubBlockEnd.gif        }

510InBlock.gif
511
InBlock.gif 
512
InBlock.gif
513InBlock.gif        public event EventHandler<WorkflowMessageEventArgs>
 ExpenseReportApproved;
514
InBlock.gif
515InBlock.gif        public event EventHandler<WorkflowMessageEventArgs>
 ExpenseReportRejected;
516
InBlock.gif
517
InBlock.gif 
518
InBlock.gif
519ExpandedSubBlockEnd.gif        #endregion

520InBlock.gif
521
InBlock.gif 
522
InBlock.gif
523InBlock.gif        private void amount_KeyPress(object
 sender, KeyPressEventArgs e)
524
InBlock.gif
525ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
526
InBlock.gif
527InBlock.gif            if (!Char.IsControl(e.KeyChar) && (!
Char.IsDigit(e.KeyChar)))
528
InBlock.gif
529InBlock.gif                e.KeyChar =
 Char.MinValue;            
530
InBlock.gif
531ExpandedSubBlockEnd.gif        }

532InBlock.gif
533
InBlock.gif 
534
InBlock.gif
535InBlock.gif        private void amount_TextChanged(object
 sender, EventArgs e)
536
InBlock.gif
537ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
538
InBlock.gif
539InBlock.gif            submitButton.Enabled = amount.Text.Length > 0
;
540
InBlock.gif
541ExpandedSubBlockEnd.gif        }

542InBlock.gif
543ExpandedSubBlockEnd.gif    }

544InBlock.gif
545
InBlock.gif 
546
InBlock.gif
547InBlock.gif    static class
 Program
548
InBlock.gif
549ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif
{
550
InBlock.gif
551ExpandedSubBlockStart.gifContractedSubBlock.gif        /**/
/// <summary>
552InBlock.gif
553InBlock.gif        ///
 The main entry point for the application.
554
InBlock.gif
555ExpandedSubBlockEnd.gif        /// </summary>

556InBlock.gif
557InBlock.gif        [STAThread]
558
InBlock.gif
559InBlock.gif        static void
 Main()
560
InBlock.gif
561ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif
{
562
InBlock.gif
563
InBlock.gif            Application.EnableVisualStyles();
564
InBlock.gif
565InBlock.gif            Application.Run(new
 MainForm());
566
InBlock.gif
567ExpandedSubBlockEnd.gif        }

568InBlock.gif
569ExpandedSubBlockEnd.gif    }

570InBlock.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.StartWorkflowType)。


来自 http://windwolfreal.cnblogs.com/archive/2005/12/18/299378.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、付费专栏及课程。

余额充值