状态机是另外一种常见的工作流类型。它是以状态的变迁为驱动而进行业务流转的,是一定需要人为干预的,而不像顺序类型工作流那样可以按照事先设计好的业务流程一步一步依次执行下去。
一、状态机工作流范例
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 > 0; i--) { this.listView1.Items.Add(states[i - 1].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:在工作流完成时执行;