VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • 坚持学习WF15 状态机工作流

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

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

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

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

  你的状态机工作流肯定要包含很多状态,那从哪一个开始呢,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.实现工作流,如下图:

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

  该工作流中主要有5个状态,如上图中所示,NotRunningState为该状态机工作流的初始状态,DoneWithCarState为结束状态,其他的都为过程结点,每个状态的左上角的图片可以标识状态的类别。

  然后我们来设置每个状态的事件,如下图:

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

  我们以NotRunningState状态的eventStartEngine为例,该EventDriven活动内包含三个子活动,一个handleStartEngine用来接收事件,对小汽车进行操作,接着是一个callExternalMethod活动,用来返回相关的信息给宿主程序,最后是一个SetState活动,来设置下一个状态。其他的状态都类似就不多介绍了。

 

  不知道你有没有注意到该状态机工作流中有一个eventBeepHorn活动,并没有在任何一个状态里,这个是因为小汽车的鸣笛动作不是一个状态,而且他在任何状态都可以做,所以我们把他放在外面,他包含一个handleBeepHorn和一个callExternalMethod活动。

  4.实现宿主程序,我们采用WinForm程序,如下图:

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

  宿主程序中我们加载本地服务,在响应的动作中调用响应的事件,具体的代码在最后的下载中。

  二:消除重复的事件处理

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

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

  这样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吧。

 

  本文示例源代码或素材下载

 

  该接口定义关于操作小汽车的一些事件,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);
      }
    }
  }
}


相关教程