`

坚持学习WF(15):状态机工作流

阅读更多

 

[置顶]坚持学习WF文章索引

本文主要介绍WF中状态机工作流的基础知识,状态机工作流和顺序型工作流不同。顺序型工作流一般是比较固定的,可预测的,和系统交互的时候比较多。而状态机工作流一般是不可预测,和人的交互会比较多一些,一般有回退流程的时候使用状态机工作流会比较好一点,如何正确的选择顺序型工作流还是状态机工作流是十分重要的。

StateMachineWorkflowActivity是状态机工作流的基类,StateActivity内可以接受多个EventDrivenActivity,一个StateInitializationActivity和一个StateFinalizationActivity。还可以包含SetStateActivity,StateActivity他们之间的关系如下图:

State1

你的状态机工作流肯定要包含很多状态,那从哪一个开始呢,StateMacnineWorkflowActivity有一个InitialStateName属性,这个属性可以设置初始的状态点。还有一个CompletedStateName属性,表示状态机工作流完成的,如果哪个状态被设置了这个属性,这个状态就不能包含任何的子活动了。这个属性不是必须设置的,是可选的。除了这两个状态其他就都是过程状态结点了。一般每个结点都会使用SetState设置下一个状态,如果没有设置的话,当所有的EventDrivenActivity执行完成后流程在当前挂起。


一:实现一个状态机工作流的例子


1.我们就已开小汽车为例子来说明,当我们开车的时候车就会有很多状态,比如未启动,运行,倒车等等状态。这些状态之间不是随便可以转换的,下面开始我们的例子,首先定义本地服务的接口,代码如下(ICarService.cs):

[ExternalDataExchange]
public interface ICarServices
{       
     event EventHandler<ExternalDataEventArgs> StartEngine;       
     event EventHandler<ExternalDataEventArgs> StopEngine;       
     event EventHandler<ExternalDataEventArgs> StopMovement;        
     event EventHandler<ExternalDataEventArgs> GoForward;
     event EventHandler<ExternalDataEventArgs> GoReverse;       
     event EventHandler<ExternalDataEventArgs> LeaveCar;
event EventHandler<ExternalDataEventArgs> BeepHorn;
     void OnSendMessage(String message);
}
该接口定义关于操作小汽车的一些事件,OnSendMessage方法会给宿主程序放回一个Message。

2.我们定义CarService类来实现这个服务,代码如下(CarService.cs):
namespace CaryStateWorkflowLibrary
{
    public class CarService : ICarServices
    {  
        public event EventHandler<ExternalDataEventArgs> StartEngine;
        public event EventHandler<ExternalDataEventArgs> StopEngine;
        public event EventHandler<ExternalDataEventArgs> StopMovement;
        public event EventHandler<ExternalDataEventArgs> GoForward;
        public event EventHandler<ExternalDataEventArgs> GoReverse;
        public event EventHandler<ExternalDataEventArgs> BeepHorn;
        public event EventHandler<ExternalDataEventArgs> LeaveCar;
public void OnSendMessage(String message) { if (MessageReceived != null) { MessageReceivedEventArgs args= new MessageReceivedEventArgs( WorkflowEnvironment.WorkflowInstanceId,message); MessageReceived(this, args); } } public event EventHandler<MessageReceivedEventArgs> MessageReceived; public void OnStartEngine(ExternalDataEventArgs args) { if (StartEngine != null) { StartEngine(null, args); } } public void OnStopEngine(ExternalDataEventArgs args) { if (StopEngine != null) { StopEngine(null, args); } } public void OnStopMovement(ExternalDataEventArgs args) { if (StopMovement != null) { StopMovement(null, args); } } public void OnGoForward(ExternalDataEventArgs args) { if (GoForward != null) { GoForward(null, args); } } public void OnGoReverse(ExternalDataEventArgs args) { if (GoReverse != null) { GoReverse(null, args); } } public void OnBeepHorn(ExternalDataEventArgs args) { if (BeepHorn != null) { BeepHorn(null, args); } } public void OnLeaveCar(ExternalDataEventArgs args) { if (LeaveCar != null) { LeaveCar(null, args); } } } }
OnSendMessage方法通过MessageReceived事件将Message传给宿主程序,MessageReceived的有一个事件参数
MessageReceivedEventArgs,该类的代码如下(MessageReceivedEventArgs.cs):
 [Serializable]
    public class MessageReceivedEventArgs : ExternalDataEventArgs
    {
        private String message;
        public MessageReceivedEventArgs(Guid instanceId, String message) : base(instanceId)
        {
            this.message = message;
        }
        public String Message
        {
            get { return message; }
            set { message = value; }
        }
    }

3.实现工作流,如下图:

State2
该工作流中主要有5个状态,如上图中所示,NotRunningState为该状态机工作流的初始状态,DoneWithCarState为结束
状态,其他的都为过程结点,每个状态的左上角的图片可以标识状态的类别。
然后我们来设置每个状态的事件,如下图:
State3 
我们以NotRunningState状态的eventStartEngine为例,该EventDriven活动内包含三个子活动,一个
handleStartEngine用来接收事件,对小汽车进行操作,接着是一个callExternalMethod活动,用来返回相关的信息给
宿主程序,最后是一个SetState活动,来设置下一个状态。其他的状态都类似就不多介绍了。
不知道你有没有注意到该状态机工作流中有一个eventBeepHorn活动,并没有在任何一个状态里,这个是因为小汽车的鸣笛
动作不是一个状态,而且他在任何状态都可以做,所以我们把他放在外面,他包含一个handleBeepHorn和一个
callExternalMethod活动。

4.实现宿主程序,我们采用WinForm程序,如下图:
State4 
宿主程序中我们加载本地服务,在响应的动作中调用响应的事件,具体的代码在最后的下载中。

二:消除重复的事件处理

在我们上面的工作流中,状态MovingForwardState和状态MovingInReverseState这两个状态中接收的是同一个事件,
都是StopMovement事件,我们来对这部分做一下重构,我们在上面工作流的基础上添加一个新的状态名字叫做MovingState
,然后将MovingForwardState和MovingInReverseState状态拖到MovingState中作为他的子活动,并将MovingForwardState
或MovingInReverseState状态中的eventStopMovement拖到MovingState中作为子活动,将MovingForwardState和
MovingInReverseState状态中的子活动删除即可,最后完成如下图:

State5
这样MovingState中的任何一个子活动都可以响应eventStopMovement中的事件,这里有一点要注意,从其他状态的
SetState依然指向原来的活动,即现在MovingState的子活动,而不是指向MovingState活动。现在再次运行程序和原来
的效果是一样的。

三:识别可用的事件




1.这部分要实现的效果如上面图片中的当我们点了StartEngine后,不可执行的动作按钮会是灰色的,我们使用WorkflowInstance
的GetWorkflowQueueData方法,根据该方法的返回值来做处理。我们在Form的构造函数添加如下代码:
btnStartEngine.Tag = "StartEngine";
btnStopEngine.Tag = "StopEngine";
btnForward.Tag = "GoForward";
btnReverse.Tag = "GoReverse";
btnStop.Tag = "StopMovement";
btnBeepHorn.Tag = "BeepHorn";
btnLeaveCar.Tag = "LeaveCar";


2.在状态机工作流中转向新的状态等待事件处理时,工作流会变成idle的状态,我们就在工作流的idle事件中来判断并设置响应的按钮是否启用,代码如下:

private void WorkflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e)
{
     UpdateDelegate theDelegate = delegate()
     {                
        EnableEventButtons(false);               .
        ReadOnlyCollection<WorkflowQueueInfo> queueInfoData = instanceWrapper.WorkflowInstance.GetWorkflowQueueData();
        if (queueInfoData != null)
        {
           foreach (WorkflowQueueInfo info in queueInfoData)
           {
               EventQueueName eventQueue = info.QueueName as EventQueueName;
               if (eventQueue == null)
               {
                   break;
               }                        
               EnableButtonForEvent(eventQueue.MethodName);
            }
         }  
     };           
     this.Invoke(theDelegate);
}

每一个WorkflowQueueInfo对象都包含一个QueueName属性,他是EventQueueName对象的一个实例,该对象有一个
MethodName属性标识当前队列中调用的外部事件的名称,我们在EnableButtonForEvent中根据tag属性和该属性来判
断,代码如下:
private void EnableButtonForEvent(String eventName)
{
    //如果控件的 Tag 属性和事件名称相同,就启用
    foreach (Control control in this.Controls)
    {
        if (control is Button &&
            control.Tag != null)
        {
            if (control.Tag.ToString() == eventName)
            {
                control.Enabled = true;
            }
        }
    }
}

这样就可以了。


四:访问运行时信息

WF中提供的StateMachineWorkflowInstance类记录了当前实例的相关信息,下面的代码来获取当前的实例。

StateMachineWorkflowInstance stateMachine = new StateMachineWorkflowInstance
(workflowManager.WorkflowRuntime,instanceWrapper.WorkflowInstance.InstanceId);
这样我们就可以得到当前实例的一些信息了,比如CurrentState,CurrentStateName等,StateHistory可以获得状
态装换的历史记录,SetState方法可以设置下一个状态等,具体就参考MSDN吧。

主要代码下载:CaryStateMachineWorkflow
分享到:
评论

相关推荐

    坚持学习WF,WF学习教程

    坚持学习WF(15):状态机工作流 本文主要介绍WF中状态机工作流的基础知识,状态机工作流和顺序型工作流不同。顺序型工作流一般是比较固定的,可预测的,和系统交互的时候比较多。而状态机工作流一般是不可预测,和人...

    坚持学习WF

    坚持学习WF(15):状态机工作流 本文主要介绍WF中状态机工作流的基础知识,状态机工作流和顺序型工作流不同。顺序型工作流一般是比较固定的,可预测的,和系统交互的时候比较多。而状态机工作流一般是不可预测,和人...

    在asp.net下用WF开发的工作流实例

    这是在asp.net下用WF开发的工作流实例,在网上找的,如果有可能的话,希望能帮到大家

    WF 状态机 订单处理的源代码

    很不错的一个基于WF,用状态机实现的工作流例子,实现持久化服务,运行时管理,人工调度服务。。。

    IMS工作流设计原理与使用方法

    1.3 状态机工作流 2.WF在Web项目中的应用 2.1 WF的应用范围 2.2 WF在WEB项目中的应用方法 2.2.1 设置工作流运行时环境 2.2.2 绘制流程图 2.2.3 事件驱动流程流转 3.IMS工作流设计原理 4.IMS工作流使用帮助 ...

    工作流引擎数据库表设计.docx

    主要考虑以下三个方面的内容: 流程定义:工作流中的流程极其相关活动的定义和模型数据搭建 运行调度控制:执行工作流过程中流程活动任务分配、调度控制 运行阶段的人机交互:实现各种活动执行过程中用户与IT应用...

    asp.net下wf设计实例

    asp.net下wf状态机工作流的完整实例,对wf学习具有极大的帮助,和大家共享

    WF (Windows Workflow Foundation) 入门向导 – 范例程序下载

    WF支持有人参与的(Human)、系统的(System)、连续的(Sequential )和状态机(State-Machine)工作流。 Workflow Foundation允许你把一个工作流定义为一系列的活动。活动即是执行的单元,并被允许轻易地进行...

    WF与WCF集成 ExpenseReporting

    这些功能使开发人员能够构建用于满足各种应用需求的工作流,从简单的顺序工作流到需要复杂的人员交互的复杂状态机工作流。 与此同时,业务能力越来越多地通过封装的服务端点展现出来,这样就可以重用和组合业务功能...

    ASP.NET WF的例子

    自己做的一个简单的ASP.NET的订单的例子,使用了状态机工作流,可以插入到数据库和更新状态,大家可以下载下来学习学习,如果有写错的请指教

    Wf+Asp.net Approval

    这个是状态机实现的 ASP.net +Wf 环境 Vs2008 .net 3.5 申请工作流

    WWF工作流

    状态机工作流实例。。。。

    WorkFlowCHM.CHM

    微软工作流workflow使用教程,BPM流程审批、OA流程审批都能用上,本教程图文并茂、通俗易懂,文章内容全部来自:https://www.cnblogs.com/foundation/。现整理成chm帮助文件,供自己学习和查询。 内容包含: (一)...

    workflow资料

    ├─状态机工作流 StateMachineWorkflowActivity │ │ StateActivity中多个EventDrivenActivity的使用说明.doc │ │ 状态容器 StateActivity.doc │ │ 状态机工作流容器 StateMachineWorkflowActivity....

    wpf源码大全 精通C#3.0图书源码 详细源码 学习好用

    SimpleStateMachine 简单的状态机示例程序。 WorkflowruntimeEvent 工作流运行时引擎事件。 第20章(\C20) 示例描述:本章介绍WF的标准活动。 CAGDemo ConditionedActivityGroup活动使用示例。 ...

    .Net.Framework3.5开发技术详解[中文][PDF][VOL1]

    作为初学入门选择方向的好教材 许多技术人员在面对.NET Framework 3.0/3.5大量的新知识、新技术的时候感到彷徨,对自己现有的技术...19.4 基于状态机的工作流 405 19.5 工作流的持久化 406 19.6 工作流的XAML表示 407

    .Net.Framework3.5开发技术详解[中文][共二卷][PDF][VOL2]

    作为初学入门选择方向的好教材 许多技术人员在面对.NET Framework 3.0/3.5大量的新知识、新技术的时候感到彷徨,对自己现有的技术...19.4 基于状态机的工作流 405 19.5 工作流的持久化 406 19.6 工作流的XAML表示 407

    .Net.Framework3.5开发技术详解

    .Net.Framework3.5开发技术详解 完整程度:99%完整 少最后8页 清晰度:一般 格式:PDF 总页数:402 内容简介 《.NET Framework3.5开发技术详解》...19.4 基于状态机的工作流 19.5 工作流的持久化 19.6 工作流的XAML表示

Global site tag (gtag.js) - Google Analytics