zoukankan      html  css  js  c++  java
  • 工作流-----WorkFlow

    我们都知道对于一个OA系统来说,最重要的也是不可或缺的一个重要环节那就是对于工作流的实现,为此,最近专门在学习如何使用WorkFlow,问前辈,前辈也说道K2工作流引擎挺不错,自己同时也翻阅了一些资料,但因为自己这个OA项目主要是采用微软的ASP.NET MVC 来开发的,所以还是决定使用微软的那一套WorkFlow工作流引擎。不得不说,微软在对于客户体验这方面做的还真是不错的。为了方面学习,我也是通过一个小案例来学习WorkFlow,在这里也拿出来和大家共同分享学习。

    小案例(请假工作流)

    说明:

    1.程序集:system.Activities

    2.Xaml文件:工作流文件设计的类型,最终会被处理为一个类

    3.状态机工作流(开发中使用的类型)

    首先:创建一个Windows窗体应用程序,命名WorkFlowDemo

    注意:为了便于工作流的展示,把当前项目的属性-----》服务,把输入类型由Windows应用程序改为控制台应用程序

    接下来,简单点设计一下窗体页面

    设计一下流程图:(状态机控件在工具箱)对于其中的工具使用,可以自己简单学习,很容易上手

    前期工作完成接下来就是代码实现的时候了,为窗体的单击按钮注册事件

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading.Tasks;
     9 using System.Windows.Forms;
    10 using System.Activities;
    11 
    12 namespace WindowsFormsApplication1
    13 {
    14     public partial class Form1 : Form
    15     {
    16         public Form1()
    17         {
    18             InitializeComponent();
    19         }
    20 
    21        //创建一个工作流对象
    22         WorkflowApplication wfapp;
    23         private void btnsave_Click(object sender, EventArgs e)
    24         {
    25 
    26             //1.准备好工作流中需要的参数
    27             Dictionary<string, object> dict = new Dictionary<string, object>();//用来向工作流传递参数
    28             dict.Add("LeaveDays", int.Parse(txtDays.Text));
    29 
    30             //2.创建一个工作流应用对象
    31             wfapp = new WorkflowApplication(new LeaveActivity(), dict);
    32 
    33       
    34             //3.调用wfapp对象的Run方法
    35             wfapp.Run();
    36         }
    37 
    38        private void btnjinli_Click(object sender, EventArgs e)
    39         {
    40             bool result = radioButton1.Checked;
    41 
    42            //唤醒书签
    43             wp.ResumeBookmark("经理审批", result);
    44         }
    45 
    46         private void button2_Click(object sender, EventArgs e)
    47         {
    48             bool result = radioButton3.Checked;
    49             wp.ResumeBookmark("财务总监审批", result);
    50         }
    51     }
    52 }
    View Code

    这时,产生了工作流中一个重要的内容------书签(BookMark)

    场景:在实际业务场景中,流程一般都是复杂的,不会一口气从开始走到最后,当在某一个需要暂停的时候,这时,书签很好的充当了这个使者,就好像我们平时看书,看到某一页突然有事要离开,但办完事回来还是要接着看的对不对,通常我们会在暂停的位置放置一个标签,等我们下次继续翻阅,可以很快的知道上一次暂停的位置。

    步骤:

    1.在项目中添加一个代码活动(CodeActivity),

    【注意】

    1. 将继承的CodeActivity父类改成NativeActivity,
    2. 同时将Execute方法中的参数也要修改为NatveActivityContext
    3. 重写父类的CanIncludeIdIe属性

    2.在该代码活动的Execute方法里创建书签

    代码实现:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Activities;
    
    namespace WindowsFormsApplication1
    {
    
        public sealed class WaitProcess :NativeActivity
        {
            //输出型参数
            public OutArgument<bool> Result { get; set; }
            //输入型参数
            public InArgument<string> BookMarkName { get; set; }
            //重写父类的CanIncludeIdIe属性
            protected override bool CanInduceIdle
            {
                get
                {
                    return true;
                }
            }
    
            protected override void Execute(NativeActivityContext context)
            {
                //创建书签
                context.CreateBookmark(context.GetValue(BookMarkName), FunCallBack);
            }
    
            private void FunCallBack(NativeActivityContext context, Bookmark bookmark, object value)
            {
    
                Console.WriteLine("工作流被唤醒");
             
                context.SetValue(Result,Convert.ToBoolean(value));
            }
    
    
        }
    }
    View Code

    操作结果:

    点击提交申请

    点击第一个审批(因为我在流程图那边设置了当天数<6时,经理审批同意后直接结束)

    别急,做到这里,也只是完成了三分之一,因为你会发现当你点击提交申请,这时,关闭整个应用程序,当你下次访问,点击审批的时候,会报错,

    这是为什么呢?因为你点击提交申请后退出,这时整个WorkFlowApplication对象也会被销毁,那么问题来了,如何做到工作流实例的具体化?

    方案有很多种,你可以采用xml文件保存,也可以把它保存到数据库,而我将采取后面那种方式,那么你又会说了,数据库我该怎么设计,别担心,微软已经帮我们写好了SQL脚本,你只需要找到它们并执行一下就好了。

    步骤:

    步骤:

    1. 建立数据表

    在C:WindowsMicrosoft.NETFrameworkv4.0.30319SQLen中可以找到两个微软写好的数据库脚本

     

    然后数据库中先执行后者脚本,在执行前者脚本

    将工作流对象往数据库中存储

    引入命名空间:

    using System.Activities.DurableInstancing;

    using System.Runtime.DurableInstancing;

    1. 什么时候持久化工作流对象?

    在工作流创建之后,为工作流对象注册一个事件:

    wfapp.PersistableIdle += a => { return PersistableIdleAction.Unload; };

    1. 创建一个SqlWorkFlowInstanceStore对象

    SqlWorkflowInstanceStore ss = new SqlWorkflowInstanceStore("server=.;daabase=WorkFlow;uid=sa;pwd=123;");

    关联持久化的工作流对象和具体的存储实例

    wfapp.InstanceStore = ss;

    1. 如何从数据库中加载未完成的工作流实例

    创建一个存储实例对象和一个工作流对象,并将它们进行关联,

    注意:重新new的WorkFlowApplication对象也要重新注册wfapp.PersistableIdle += a => { return PersistableIdleAction.Unload; };这个事件

    最后调用WorkFlowApplication对象的Load(Guid guid)方法

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Activities;
    using System.Activities.DurableInstancing;
    using System.Runtime.DurableInstancing;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            WorkflowApplication wfapp;
            private void btnsave_Click(object sender, EventArgs e)
            {
      
    
                //1.准备好工作流中需要的参数
                Dictionary<string, object> dict = new Dictionary<string, object>();//用来向工作流传递参数
                dict.Add("LeaveDays", int.Parse(txtDays.Text));
                //2.创建一个工作流应用对象
                wfapp = new WorkflowApplication(new LeaveActivity(), dict);
    
                //在工作流创建之后,为工作流对象注册一个事件
                wfapp.PersistableIdle += a => { return PersistableIdleAction.Unload; };
    
                //关联持久化的工作流对象和具体的存储实例
                SqlWorkflowInstanceStore ss = new SqlWorkflowInstanceStore("server=.;daabase=WorkFlow;uid=sa;pwd=123;");
                wfapp.InstanceStore = ss;
                //3.调用wfapp的Run方法
                wfapp.Run();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
               
    
                //从数据中加载实例
                SqlWorkflowInstanceStore ss = new SqlWorkflowInstanceStore("server=.;daabase=WorkFlow;uid=sa;pwd=123;");
                wfapp = new WorkflowApplication(new LeaveActivity());
                wfapp.PersistableIdle += a => { return PersistableIdleAction.Unload; };
                wfapp.InstanceStore = ss;
                //wfapp.Load("CA15C81C-FE95-4B0B-B1F4-B5F1478BEF3C");//传入的是一个guid参数
                bool result = radioButton1.Checked;
                //唤醒书签
                wfapp.ResumeBookmark("经理审批", result);
            }
        }
    }
    View Code

    效果图:

    你会发现在你的数据库表中多了一条记录,这时记录了你上一次未完成的操作(把这个Guid复制下来,放到按钮1审批的代码中Load方法中)因为是做测试用

    第二次在运行,直接点击经理审批对应的审批按钮,你会发现:

    同时数据库中的记录也不见了

    好了,具体实现就这么多了,但是还存在一个问题,那就是对于某个按钮事件,你会发现重复性的代码太多了,不妨就自己去进行封装吧!做成一个属于自己的Helper!

    最后,非常希望大家可以提出批评和建议。谢谢!

  • 相关阅读:
    < java.util >-- Set接口
    Codeforces 627 A. XOR Equation (数学)
    Codeforces 161 B. Discounts (贪心)
    Codeforces 161 D. Distance in Tree (树dp)
    HDU 5534 Partial Tree (完全背包变形)
    HDU 5927 Auxiliary Set (dfs)
    Codeforces 27E. Number With The Given Amount Of Divisors (暴力)
    lght oj 1257
    Codeforces 219D. Choosing Capital for Treeland (树dp)
    Codeforces 479E. Riding in a Lift (dp + 前缀和优化)
  • 原文地址:https://www.cnblogs.com/xrk1203/p/6681608.html
Copyright © 2011-2022 走看看