简介
WF兼有很多角色,如编程模型、运行时引擎以及工具集等,它使我们很容易创建基于工作流的应用。这里主要分析一下VS2008下顺序工作流控制台应用程序的模板,并了解几个常见的活动。
顺序工作流控制台应用程序模板
WF提供两种类型的工作流:顺序工作流、状态机工作流。这两个工作流分别从SequentialWorkflowActivity, StateMachineWorkflowActivity派生而来。VS2008提供了顺序工作流控制台应用程序和类库两种模板,本文主要介绍顺序工作流控制台应用程序模板。
创建工作流项目
具体步骤省略,详细请参见参考文献所示。查看生成的工作流代码如下:
Code
public sealed partial class Workflow1: SequentialWorkflowActivity
{
public Workflow1()
{
InitializeComponent();
}
}
很容易看出,新建的工作流Workflow1是从SequentialWorkflowActivity派生。
新建的工作流只有起始点,没有任何活动。这里我们添加一个Code activity。添加了这个活动后,我们发现,这个活动出现了错误,是因为ExecuteCode没有设定,这里只需双击Code activity即可,并在代码文件中添加Console.WriteLine("Hello, World!");。一个Hello, World!工作流就这样完成了。
解析工作流调用代码(宿主程序代码)
Code
static void Main(string[] args)
{
// 创建工作流运行时引擎,为工作流初始化提供可配置的运行环境
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
// 防止工作流线程没有执行完成,主线程就退出。
// 工作流线程完成后,通过Set方法通知主线程,工作流线程已经完成。
AutoResetEvent waitHandle = new AutoResetEvent(false); // AutoResetEvent表示通知正在等待的线程已发生事件,false表示初始状态非中止
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set(); // 通知主线程,工作流执行完毕
};
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set(); // 通知主线程,工作流执行完毕
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowDemo1.Workflow1));
instance.Start();
// 主线程在此阻塞,直到工作流线程发出通知(waitHandle.Set())
waitHandle.WaitOne();
}
}
注意:
1. 通过WorkflowRuntime类为工作流初始化提供可配置的运行环境
2. 通过AutoResetEvent类,协调主线程和工作流线程。
3. 通过WorkflowInstance类创建工作流实例。
创建一个比Hello, World更高级的工作流
作业:创建一个工作流,使之支持一个文件加中的所有文件拷贝到另外一个文件夹。
思路:
1.创建一个代码活动,解析从宿主程序传来的源文件夹和目的文件夹;
2.创建一个循环活动(一个个拷贝,直到所有文件拷贝完毕)
在循环活动中嵌入代码活动,完成单个文件的拷贝
这里需要解释几个问题:
循环活动条件设置
在while activity活动中,规则采用声明性规则条件,当前是第几个文件 < 总共几个文件。在后台生成如下文件workflow.rules:
Code
<RuleDefinitions xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<RuleDefinitions.Conditions>
<RuleExpressionCondition Name="条件1">
<RuleExpressionCondition.Expression>
<!--操作符定义为小于号-->
<ns0:CodeBinaryOperatorExpression Operator="LessThan" xmlns:ns0="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<!--左边的值-->
<ns0:CodeBinaryOperatorExpression.Left>
<ns0:CodeFieldReferenceExpression FieldName="currentFile">
<ns0:CodeFieldReferenceExpression.TargetObject>
<ns0:CodeThisReferenceExpression />
</ns0:CodeFieldReferenceExpression.TargetObject>
</ns0:CodeFieldReferenceExpression>
</ns0:CodeBinaryOperatorExpression.Left>
<!--右边的值-->
<ns0:CodeBinaryOperatorExpression.Right>
<ns0:CodePropertyReferenceExpression PropertyName="totalFiles">
<ns0:CodePropertyReferenceExpression.TargetObject>
<ns0:CodeThisReferenceExpression />
</ns0:CodePropertyReferenceExpression.TargetObject>
</ns0:CodePropertyReferenceExpression>
</ns0:CodeBinaryOperatorExpression.Right>
</ns0:CodeBinaryOperatorExpression>
</RuleExpressionCondition.Expression>
</RuleExpressionCondition>
</RuleDefinitions.Conditions>
</RuleDefinitions>
在后台,通过
System.Workflow.Activities.Rules.RuleConditionReference ruleconditionreference1 = new System.Workflow.Activities.Rules.RuleConditionReference();
ruleconditionreference1.ConditionName = "条件1";
this.whileActivity1.Condition = ruleconditionreference1;
进行加载到循环活动中。
宿主程序和工作流的通讯
如何向工作流中传递参数:
在工作流中定义成员变量:
public string toFolder { get; set; }
public string fromFolder { get; set; }
public int totalFiles { get; set; }
在宿主程序初始化工作流实例的时候,将参数传入
var parameters = new Dictionary<string, object>();
parameters.Add("fromFolder", @"K:"test");
parameters.Add("toFolder", @"K:"backup");
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(
typeof(WorkflowDemo1.Workflow1), parameters);
如何从工作流中获取参数:
从WorkflowCompletedEventArgs e 中,即可获取工作流中的相关信息,如:e.OutputParameters["totalFiles"]。
参考文献
本翻译没有按照原文,详细请查阅
http://social.msdn.microsoft.com/content/en-us/msft/netframework/wf/learn/Intro-SequentialWorkflows