• 宿主和工作流:两个世界的交互 4(Host给工作流传递数据) Virus


         原文地址:
          http://www.codeproject.com/KB/WF/host_wf_comm_P4.aspx
           到目前为止我们已经知道了Host和工作流交互的重点,现在我们要做一点小东西,使得我们的工作容易一些,如何用面向对象来组织我们的工作。
          从前面的章节中我们看到,使用CallExternalMethod 和HandleExternalEvent活动来实现这些是可以的,但是如果我们有一个复杂的工作流,该使用那些活动可能就变得迷惑了。
          workflow的SDK提供了一个自动添加所需CallExternalMethod 和HandleExternalEvent活动的工具,可以减轻我们的工作,使得工作流很容易理解。
          wca.exe直接使用从dll中获取的必要信息来创建常用活动,dll是我们定义的外部交互接口。工具需要设置一些选项来生成常用行为。因为控制台程序通常比较复杂,因为数据的路径或者程序自己越来越复杂,作者写了一个小winform工具,可以免费获取。WWCA.ZIP 
          wf11.JPG
          在使用这个小程序之前,要存储wca.exe的目录(可以参照C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin),在wwca.exe的配置菜单中设置。
          如你看到的,工具只需要你的自定义交互服务的目录作为输入,他就会很容易的检查不同的输入参数和选项。
          在前面我们开发的在Host中迁入工作流和交互服务没有任务的面向对象。那是因为我们的交互服务没有包装起来。
          在这篇中,我们将创建一个交互管理类来驱动所有和交互有关系的。
          好的,我们使用一个简单的程序控制一个简单的值。值可以被一个按钮驱动,另外一个按钮来驱动打开或者关闭这个值的状态。
          有一条简单的业务规则,当值是关闭状态的话,值可以power off;如果值是打开状态  ,你不可以power off。
          我们将使用一个状态机工作流来控制值得状态,用户的接口是一个winform的程序。
          wf22.JPG
          上图是这个程序的架构。
          代码开发
          1、交互管理器
          从上面的图中我们可以看到Host是如何和工作流进行交互的 。
                从工作流到Host:我们需要一个外部方法来返回状态信息给Host,你可以定义一些返回信息为字符串,例如,CLOSE OPEN EXIT INIT
                从Host到工作流:这里你有两种选择,每个状态改变对应一个事件或者事件带一个新状态作为参数
          我在这里选择每一个状态对应一个事件,这样我就不需要创建一个特殊的事件参数,我可以直接使用ExternalDataEventArgs 参数,因为我在参数中不需要传递自定义的信息。
          我们需要声明三个事件,分别是:open,close,exit。不需要声明init,因为你创建工作流的时候你就是init。
          首先创建下面的接口

    [ExternalDataExchange]
    public interface ICommunicationValve
    {
    #region Communication WF -> Host
      ///
     <summary>
      
    /// Used by CallExternalEvent Argument to pass the valve
      
    /// status to Host
      
    /// </summary>
      ///
     <param name="status">Actual statis for valve</param>
      
    void StatusValve(Guid wfGuid, string status);
    #endregion

    #region
     Communication Host -> WF
      ///
     <summary>Use to pass the valve operation to workflow
      
    ///</summary>
      
    event EventHandler<ExternalDataEventArgs> CloseValve;
      
    /// <summary>Use to pass the valve operation to workflow
      
    ///</summary>
      
    event EventHandler<ExternalDataEventArgs> Exit;
      
    /// <summary>Use to pass the valve operation to workflow
      
    ///</summary>
      
    event EventHandler<ExternalDataEventArgs> OpenValve;

    #endregion

    }//
    end ICommunicationValve

    接下来要做的就是实现这个接口,因为我们这里是一个winform程序,因此我们需要在StatusValve 方法中实现一个内部的事件,通过事件传递信息给表单。

    public class CommunicationValve : ICommunicationValve
    {
      
    #region WF -> Host Communication
      public
     event EventHandler<ExternalValveEventArgs>
      EventValveStatus;

      ///
     <summary>
      
    /// Used by CallExternalEvent Argument to pass the valve 
      
    ///status to Host
      
    /// </summary>
      ///
     <param name="status">Valve status OPEN / CLOSE / EXIT</param>
      
    public void StatusValve(Guid wfGuid, string status)
      {
         
    if (EventValveStatus != null)
         {
            ExternalValveEventArgs e 
    = new ExternalValveEventArgs(wfGuid);
            e.Status 
    = status;
            EventValveStatus(
    this, e); //Raise the event
      }

    }

    #endregion

    #region
     Host -> WF
      ///
     <summary>
      
    /// Use to pass the valve operation to workflow
      
    /// </summary>
      
    public event EventHandler<ExternalDataEventArgs> CloseValve;

      
    /// <summary>
      
    /// Use to pass the valve operation to workflow
      
    /// </summary>
      
    public event EventHandler<ExternalDataEventArgs> Exit;

      
    /// <summary>
      
    /// Use to pass the valve operation to workflow
      
    /// </summary>
      
    public event EventHandler<ExternalDataEventArgs> OpenValve;

    #endregion

    #region
     Auxiliar procedures

      ///
     <summary>
      
    /// Raise the event Exit
      
    /// </summary>
      ///
     <param name="instanceId">workflow instance</param>

      public
     void RaiseExit(Guid instanceId)
      {

         
    if (Exit != null)
         {
            ExternalDataEventArgs e 
    = new ExternalDataEventArgs(instanceId);
            e.WaitForIdle 
    = true;
            Exit(
    null, e);
         }
      }

      
    /// <summary>
      
    /// Raise the event Open
      
    /// </summary>
      ///
     <param name="instanceId">workflow instance</param>
      
    public void RaiseOpen(Guid instanceId)
      {
        
    if (OpenValve != null)
        {
           ExternalDataEventArgs e 
    = new ExternalDataEventArgs(instanceId);
          OpenValve(
    null, e);
        }
      }
      
    /// <summary>
      
    /// Raise the event Close
      
    /// </summary>
      ///
     <param name="instanceId">workflow instance</param>
      
    public void RaiseClose(Guid instanceId)
      {
        
    if (CloseValve != null)
        {
           ExternalDataEventArgs e 
    = new ExternalDataEventArgs(instanceId);
           CloseValve(
    null, e);
        }
      }
    #endregion
    }
    //end CommunicationValve

          如你所看到的,我们直接在实现接口的类中包装了激发事件的方法,这样你就不需要在外部激发事件。
          就像你在前面的章节中看到的,你需要在工作流运行时中注册这个服务为你的交互服务。那么创建一个包装这些活动的对象是一个好主意。这里我们创建一个交互管理类,这个类一定只能包含一个CommunicationValve 类的实例,一个工作流运行时的引用。
          代码如下
    public class CommunicationManager 
    {

      
    /// <summary>
      
    /// Single onject of the communicationValve class.
      
    /// </summary>
      
    private static CommunicationValve Comvalve = null;

      
    /// <summary>
      
    /// Reference to the workflow runtime.
      
    /// </summary>
      
    private WorkflowRuntime runtime = null;

      
    /// <summary>
      
    /// Return the CommunicationValve instance.
      
    /// </summary>
      
    public CommunicationValve Valve
      {
        
    get
          {
            
    return Comvalve;
          }
      }

      
    /// <summary>Constructor Communication manager</summary>
      ///
     <param name="wfRuntime">Runtime instance</param>
      
    public CommunicationManager(WorkflowRuntime wfRuntime)
      {
        runtime 
    = wfRuntime;
        
    if (Comvalve == null)
        {
          Comvalve 
    = new CommunicationValve();
        }
      }

      
    /// <summary>
      
    /// Procedure to register the communication service.
      
    /// </summary>
      
    public void RegisterCommunicationService()
      {
        
    //Declare a ExternalDataExchangeService class
        ExternalDataExchangeService dataservice 
    = new
        ExternalDataExchangeService();
        //
    Add to workflow runtime
        runtime.AddService(dataservice);
        
    //Add to the ExternalDataService
        dataservice.AddService(Comvalve);
      }
    }
    //end CommunicationManager


          我们可以应用一个假象概念,在这个管理类中声明一个触发ValveCommunication 类中事件的方法,而不是直接调用ComValve 实例。
          我们已经有了自己的管理类,全部的类关系图如下图
    wf33.JPG
    2、应用工作流
          创建一个状态机工作流库项目,我们要做的第一布就是建立自定义行为。
          打开wwca.exe程序,选择在前面创建的dll,也就是CommunicationManager。选择输出工作路的路径,选择option中的include sender ,填写   在你的项目中使用的命名空间。
          然后选择【action】-》【Execute wca】,如果操作正确的话,在下面的结果中就会看见内容,wca.exe发送的控制信息。
          

    【Blog】http://virusswb.cnblogs.com/

    【MSN】jorden008@hotmail.com

    【说明】转载请标明出处,谢谢

    反馈文章质量,你可以通过快速通道评论:

  • 相关阅读:
    如何在dede栏目设置中添加自定义字段(dede二次开发-纯抄贴)
    dedecms内容页 上下篇 添加文章描述方法
    关于透明层----背景透明字不透明的效果
    什么是JavaScript闭包终极全解之一——基础概念
    phpcms v9中调用多栏目的方法--get标签(备实例)
    PHP识别电脑还是手机访问网站
    PHP中 post 与get的区别 详细说明
    js 处理数据里面的空格
    mysql中的unix_timestamp函数
    PHP中date函数月和日带0问题
  • 原文地址:https://www.cnblogs.com/virusswb/p/1341119.html
Copyright © 2020-2023  润新知