• 工作流-----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!

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

  • 相关阅读:
    不使用库函数,编写函数int strcmp(char *source, char *dest) 相等返回0,不等返回-1【转】
    atol实现【转】
    atol的实现【转】
    关于内存中栈和堆的区别(非数据结构中的堆和栈,区别)【转】
    ubuntu下安装android模拟器genymotion【转】
    buntu下命令行安装jdk,android-studio,及genymotion虚拟机来进行android开发【转】
    Ubuntu下安装Android studio【转】
    C++模板(二)【转】
    【转】iOS中设置导航栏标题的字体颜色和大小
    【转】Java 截取字符串
  • 原文地址:https://www.cnblogs.com/xrk1203/p/6681608.html
Copyright © 2020-2023  润新知