WWF3状态机工作流<WWF第七篇>
状态机是另外一种常见的工作流类型。它是以状态的变迁为驱动而进行业务流转的,是一定需要人为干预的,而不像顺序类型工作流那样可以按照事先设计好的业务流程一步一步依次执行下去。
一、状态机工作流范例
State活动有三种状态类型:
- 起始状态;
- 业务逻辑过程状态;
- 终止状态;
在一个状态机工作流中起始状态和终止状态只能有一个。状态机工作流是从起始状态开始执行,在运行过程中通过业务员逻辑状态的变迁来进行工作流的流转,最终由终止状态标记工作流的结束。因此在状态机工作流设计界面上只能添加"State"状态活动,另外在该状态中还可以添加一个或多个"EventDriven(事件驱动活动)"。
状态机工作流中大量使用HandleExternalEvent活动来接收应用程序的操作,从而改变工作流上运行表单的业务状态,因此需要定义一个接口程序作为工作流和应用程序之间沟通的桥梁。
默认的状态机工作流界面图:

在状态机工作流程序中需要指明哪个"State"活动是最先起始的活动,哪个"State"活动是最终结束的活动。

可以通过点击"State"活动的右键菜单进行设置:

通过拖动EventDriven活动左右两边的节点就可以建立状态间的变迁关系。
工作流看似简单,实际上里面还要设置,双击每个EventDriven活动,为它添加一个HandleExternalEvent子活动,并将HandleExternalEvent子活动与接口项目中定义的事件依次绑定。

Winform程序界面如下:

其完成代码如下所示:
public partial class Form1 : Form, ClassLibrary1.IEvent
{
public event EventHandler<ExternalDataEventArgs> Event1;
public event EventHandler<ExternalDataEventArgs> Event2;
public event EventHandler<ExternalDataEventArgs> Event3; public WorkflowRuntime workflowruntime;
private WorkflowInstance workflowinstance;
private ExternalDataExchangeService exterserv;
static AutoResetEvent waitHandle = new AutoResetEvent(false); //为了得到状态机工作流还运行中的变迁情况,例子使用了StateMachineInstanceStateHistory来获取状态机的状态。
//但使用"StateHistory"必须启动WWF工作流的"Persistence"和“Tracking”服务。
const string connectionTrackingString = "Initial Catalog=Tracking;Data Source=localhost;Integrated Security=SSPI;";
const string connectionPersistenceString = "Initial Catalog=SqlPersistenceService;Data Source=localhost;Integrated Security=SSPI;"; public Form1()
{
InitializeComponent(); workflowruntime = new WorkflowRuntime();
exterserv = new ExternalDataExchangeService(); workflowruntime.WorkflowIdled += OnWorkflowIdled;
workflowruntime.WorkflowCompleted += OnWorkflowCompleted; //分别创建"Persistence"与"Persistence"服务,并将它们加载到工作流的运行时容器Runtime中。
workflowruntime.AddService(new SqlTrackingService(connectionTrackingString));
WorkflowPersistenceService persistenceService = new SqlWorkflowPersistenceService(connectionPersistenceString);
workflowruntime.AddService(persistenceService); workflowruntime.AddService(exterserv);
exterserv.AddService(this); workflowruntime.StartRuntime(); Type wftype = typeof(WorkflowConsoleApplication1.Workflow1);
workflowinstance = workflowruntime.CreateWorkflow(wftype);
workflowinstance.Start();
} public void OnWorkflowIdled(object sender, WorkflowEventArgs e)
{
e.WorkflowInstance.TryUnload(); GetStateHistory addListItem = new GetStateHistory(GetStateHistorysync);
Invoke(addListItem, e.WorkflowInstance.InstanceId);
waitHandle.Set();
} public void OnWorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
Addstring addListItem = new Addstring(Addstringsync);
Invoke(addListItem, "结束");
waitHandle.Set();
} private void btn1_Click(object sender, EventArgs e)
{
Event1(null, new ExternalDataEventArgs(workflowinstance.InstanceId));
this.btn1.Enabled = false;
} private void btn2_Click(object sender, EventArgs e)
{
Event2(null, new ExternalDataEventArgs(workflowinstance.InstanceId));
this.btn2.Enabled = false;
} private void btn3_Click(object sender, EventArgs e)
{
Event3(null, new ExternalDataEventArgs(workflowinstance.InstanceId));
this.btn3.Enabled = false;
} //将每一步的状态变化取出来显示在列表中。通过"委托"代理啊在工作流的"OnWorkflowIdled"事件中被调用。
private delegate void GetStateHistory(Guid id);
public void GetStateHistorysync(Guid id)
{
StateMachineWorkflowInstance StateMachineInstance = new StateMachineWorkflowInstance(workflowruntime, id);
ReadOnlyCollection<string> states = StateMachineInstance.StateHistory;
for (int i = states.Count; i > ; i--)
{
this.listView1.Items.Add(states[i - ].ToString());
}
} private delegate void Addstring(string str);
public void Addstringsync(string str)
{
this.listView1.Items.Add(str);
}
}
运行后可以看到其状态的切换:

二、StateInitialization和StateFinalization活动
在上面的例子中,我们看到了WorkflowStarted与WorkflowCompleted两个事件,分别代表工作流的启动与结束。但在"State"状态活动的属性窗口中却找不到相应的开始和结束事件。WWF专门为"State"活动设计了两个子活动"StateInitialization"和"StateFinalization"来实现相应的功能。
状态机工作流都需要人为干预,因此都有对应的接口程序以便于HandleExternalEvent活动进行绑定。
接口代码:
[ExternalDataExchange] //using System.Workflow.Activities;
public interface IEvent
{
event EventHandler<ExternalDataEventArgs> Event1;
}
创建一个状态机工作流项目,在工作流设计界面上添加两个"State"活动,并且将其分别命名为"提交申请"和"结束",然后通过右键菜单将它们分别设置为工作流的"启动"和"终止"状态。
在"提交申请"状态中添加EventDriven子活动,并且在该EventDriven活动中添加HandleExternalEvent子活动,然后与接口项目中定义的"Event1"事件进行绑定。
完成后的工作流界面如下所示:



状态机工作流的"起始"类型状态和"业务逻辑过程"类型的状态可以添加"StateInitialization","StateFinalization"子活动,"终止"类型的状态是不能添加这两个子活动的。
在右键菜单中通过"添加 StateInitialization"和"添加 StateFinalization",又或者从工具栏中将子活动直接添加到"State"活动中,"StateInitialization"和"StateFinalization"子活动只是一个普通的容器类型活动,它们会在"State"活动开始和结束时分别被触发,这就可以起到类似于Window窗体"Load"事件和"FormClosed"事件的作用。

更好地观察"StateInitialization"和"StateFinalization"子活动,和EventDriven子活动之间的运行顺序,可以向这两个子活动里面分别添加一个Code,然后绑定一个弹出窗口事件。工作流代码如下:
public sealed partial class Workflow1 : StateMachineWorkflowActivity
{
public Workflow1()
{
InitializeComponent();
} private void Code1Execute(object sender, EventArgs e)
{
MessageBox.Show("StateInitialization开始执行!");
} private void Code2Execute(object sender, EventArgs e)
{
MessageBox.Show("StateFinalization开始执行!");
} private void handleExternalExecute(object sender, ExternalDataEventArgs e)
{
MessageBox.Show("handleExternalEvent开始执行!");
}
}
创建一个WinForm程序,只有一个按钮,界面如下:

Winform程序代码如下:
public partial class Form1 : Form, ClassLibrary1.IEvent
{
public event EventHandler<ExternalDataEventArgs> Event1; public WorkflowRuntime workflowruntime;
private WorkflowInstance workflowinstance;
private ExternalDataExchangeService exterserv;
static AutoResetEvent waitHandle = new AutoResetEvent(false); public Form1()
{
InitializeComponent(); workflowruntime = new WorkflowRuntime();
exterserv = new ExternalDataExchangeService(); workflowruntime.AddService(exterserv);
exterserv.AddService(this); workflowruntime.StartRuntime(); Type wftype = typeof(WorkflowConsoleApplication1.Workflow1);
workflowinstance = workflowruntime.CreateWorkflow(wftype);
workflowinstance.Start();
} private void btn1_Click(object sender, EventArgs e)
{
Event1(null, new ExternalDataEventArgs(workflowinstance.InstanceId));
}
}
弹出对话框顺序如下,启动程序,未点按钮:

点击提交按钮后:

- StateInitialization:在工作流启动时执行;
- StateFinalization:在工作流完成时执行;
WWF3状态机工作流<WWF第七篇>的更多相关文章
- WWF3追踪功能<WWF第六篇>
WWF工作流提供了Tracking跟踪功能来对工作流实例及其所包含的活动在运行时的状态进行跟踪,以便用户在需要时可以通过这些历史信息进行分析.WWF的Tracking跟踪功能是通过"SqlT ...
- 第七篇 Integration Services:中级工作流管理
本篇文章是Integration Services系列的第七篇,详细内容请参考原文. 简介在上一篇文章,我们创建了一个新的SSIS包,学习了SSIS中的脚本任务和优先约束,并检查包的MaxConcur ...
- 第七篇 SQL Server代理作业活动监视器
本篇文章是SQL Server代理系列的第七篇,详细内容请参考原文 在这一系列的上一篇,你创建并配置SQL Server代理作业.每个作业有一个或多个步骤,可能包含大量的工作流.在这篇文章中,将查看作 ...
- 【译】第七篇 Integration Services:中级工作流管理
本篇文章是Integration Services系列的第七篇,详细内容请参考原文. 简介在上一篇文章,我们创建了一个新的SSIS包,学习了SSIS中的脚本任务和优先约束,并检查包的MaxConcur ...
- 【译】第七篇 SQL Server代理作业活动监视器
本篇文章是SQL Server代理系列的第七篇,详细内容请参考原文 在这一系列的上一篇,你创建并配置SQL Server代理作业.每个作业有一个或多个步骤,可能包含大量的工作流.在这篇文章中,将查看作 ...
- Workflow笔记2——状态机工作流
状态机工作流 在上一节Workflow笔记1——工作流介绍中,介绍的是流程图工作流,后来微软又推出了状态机工作流,它比流程图功能更加强大. 状态机工作流:就是将工作流系统中的所有的工作节点都可以看做成 ...
- SharePoint 2013 状态机工作流之扩展自定义状态
当我们使用SharePoint 2013的状态机工作流时,发现一个非常不爽的事情,就是SharePoint 所有的工作流状态,都是固定的那些,没办法显示我们自定义的状态,后来经过Google发现,原来 ...
- SharePoint 2013 状态机工作流之日常报销示例
简单介绍下状态机工作流,状态机工作流提供了一系列的状态.工作流从初始状态开始,到终止状态结束.两个状态之间定义行为进行过渡.通常情况下,状态机工作流对事件作出反应,事件的发生将会使状态发生改变. 1. ...
- 解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译)
解剖SQLSERVER 第七篇 OrcaMDF 特性概述(译) http://improve.dk/orcamdf-feature-recap/ 时间过得真快,这已经过了大概四个月了自从我最初介绍我 ...
随机推荐
- NeHe OpenGL教程 第二十四课:扩展
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- iis7 500错误日志报 LOG_FILE_MAX_SIZE_TRUNCATE
参考:http://blogs.iis.net/robert_mcmurray/freb-log-file-max-size-truncate cd /d "%windir%\system3 ...
- 错误代码2104:无法下载Silverlight应用程序。请查看Web服务器设置
今天调试Silverlight程序,把ClientBin文件夹下的.xap文件删除后遇到这样一个问题:错误代码2104:无法下载Silverlight应用程序.请查看Web服务器设置.在网上查了一下, ...
- Win8下修改任務欄的資源管理器默認打開位置
不能像win7一樣右鍵屬性改了,但還是有辦法的. 新建一個文件夾,建立快捷方式,右鍵快捷方式,將目標改為%windir%\explorer.exe /n,/e,D:\Desktop 然後將該快捷方式拖 ...
- map遍历测试结果
结论:一般情况下推荐使用enterSet的for循环(即以下的方法2),如果只是取key值可以使用keySet性能会更好. 因为keySet只取key,enterSet即取了key又取了value. ...
- java反射机制详解 及 Method.invoke解释
JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为ja ...
- mysql 如何用root 登录
mysql -uroot -p 如果没有密码,按两下回车就进去了
- [SQL]循环插入数据,并且计算插入所用时间
--得出以上速度的方法是:在各个select语句前加: declare @d datetime set @d=getdate() select * from tb --并在select语句后加: se ...
- POJ 1611
菜鸟第一次做这种.想了好一会儿.== 首先还是初始化记忆数组,使得每一个元素的初始根节点是自己. 然后是对输入的数据进行并集.我们拿出每组元素的第一个作为根节点. 每次检测是否已经存在根节点.如果存在 ...
- nyoj 106 背包问题
点击打开链接 背包问题 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v ...