WorkFlow工作流
一、WorkFlow介绍
1. WorkFlow是OA系统中必不可少的模块,并且在以后的大多数的工作中,都会用到工作流模式的开发。关于这方面的开发,我第一次接触到的是关于钉钉里的氚云功能,感觉还是做的相当不错,用户只需要拖动控件,然后配置数据库,就会形成对应的工作流,并不需要大量的代码编写。
二、创建一个demo案例:
1. 这儿创建的是一个控制台程序demo。
主程序代码如下:
using System; using System.Linq; using System.Activities; //主要的 using System.Activities.Statements; namespace WorkflowConsoleApplication1 { class Program { static void Main(string[] args) { //new了一个工作流类 Activity workflow1 = new Workflow1(); //启动工作流 WorkflowInvoker.Invoke(workflow1); Console.ReadLine(); } } }
其中需要注意的是inputCodeActivity1,该控件是一个代码活动,就是指此处需要一些别的操作,具体创建如下:
并且编辑如下代码,提供一个返回参数:
public sealed class inputCodeActivity1 : CodeActivity { // 定义一个字符串类型的活动输入参数 //public InArgument<string> Text { get; set; } //输出参数 public OutArgument<int> returnMoney { get; set; } // 如果活动返回值,则从 CodeActivity<TResult> // 派生并从 Execute 方法返回该值。 protected override void Execute(CodeActivityContext context) { // 获取 Text 输入参数的运行时值 //string text = context.GetValue(this.Text); int m; string money = Console.ReadLine(); int.TryParse(money, out m); //为输出参数设置参数 context.SetValue(returnMoney,m); } }
最终全部创建好,之后,如下:
最终的运行结果如下:
备注:4.0版本的没有状态机工作流,需要切换到别的版本才有
三、 WorkflowApplication启用工作流以及传参,与常用触发事件。
1. WorkflowApplication提供了很多的触发事件,每当工作流执行到某一状态的时候,就会触发该工作流里的方法,并且进行实时监控,所以目前工作流的启动,都是使用该类来完成。
2. case:
定义一个winform窗体应用界面
button对应代码如下:
private void btnStartWorkFlow_Click(object sender, EventArgs e) { //定义一个字典 var dict = new Dictionary<string, object>() { { "tempDateTime", DateTime.Now } }; //工作流的类, //WorkflowApplication wfApp = new WorkflowApplication(new Activity1()); //重载的第二种,传递一个参数过去,但是必须是键值对的形式。 WorkflowApplication wfApp = new WorkflowApplication(new Activity1(),dict); //信号量机制类 AutoResetEvent syncEvent = new AutoResetEvent(false); wfApp.Run(); }
工作流中如下:此处的参数必须和传递的参数值一致。
3. 常用触发事件。
private void btnStartWorkFlow_Click(object sender, EventArgs ex) { Console.WriteLine("主线程:"+Thread.CurrentThread.ManagedThreadId); var dict = new Dictionary<string, object>() { { "TempDateTime", DateTime.Now }, { "TempBookMarkName",this.txtBookMarkName.Text} }; AutoResetEvent syncEvent = new AutoResetEvent(false); //主线程信号量 wfApp = new WorkflowApplication(new Activity1(), dict);//第二个参数是给工作流传参,这里的参数名TempDateTime,必须和工作流中定义的参数名称一致. //-----------------------常用触发事件--------------------- //工作流执行完成之后触发里面代码, wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e) { Console.WriteLine("工作流执行完成"); syncEvent.Set(); //唤起主线程 }; //强制终止触发 wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e) { Console.WriteLine("工作流终止"); syncEvent.Set(); }; //处于空闲状态触发 wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e) { Console.WriteLine("工作流空闲"); syncEvent.Set(); }; //工作流持久化,就是指例如把当前的数据录入到数据库中 wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e) { Console.WriteLine("工作流持久化"); syncEvent.Set(); return PersistableIdleAction.Unload; //工作流卸载 }; //卸载之后触发 wfApp.Unloaded = delegate(WorkflowApplicationEventArgs e) { Console.WriteLine("工作流卸载"); syncEvent.Set(); }; //发生异常触发的时间 wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e) { Console.WriteLine("工作流异常了"); syncEvent.Set(); return UnhandledExceptionAction.Abort; }; // Start the workflow. wfApp.Run();//开始执行设计好的工作流,这里会会开启一个新的线程。 syncEvent.WaitOne(); //阻止主线程,直到当前收到信号。 Console.WriteLine("继续执行后面的代码"); }
四、线程信号量类介绍:
1. new一个线程信号量
AutoResetEvent syncEvent = new AutoResetEvent(false); //主线程信号量
上方代码中主要使用到了如下两个方法;
syncEvent.Set(); //唤起主线程
syncEvent.WaitOne(); //阻止主线程,直到当前收到信号。
五、 BookMark(书签)
1. 就是指执行到该结点处暂停,等待开启的命令,然后继续执行。
2. 就是指修改创建的代码活动类。本来是继承CodeActivity类,现在改为继承NativeActivity,并且重新其中提供的抽象方法,注释掉原本的方法,创建Bookmark书签,需要提供两个参数,一个是书签名,一个是需要执行的方法,相关代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Activities; namespace WindowsFormsApplication1 { //修改使其继承 NativeActivity public sealed class Wait4BookMarkCodeActivity :NativeActivity { // 定义一个字符串类型的活动输入参数 public InArgument<string> BookMarkName { get; set; } public OutArgument<int> ReturnResult { get; set; } // 如果活动返回值,则从 CodeActivity<TResult> // 派生并从 Execute 方法返回该值。 //protected override void Execute(CodeActivityContext context) //{ // // 获取 Text 输入参数的运行时值 // string text = context.GetValue(this.Text); //} /// <summary> /// 自动调用该方法,在该方法中完成BookMark的创建 /// </summary> /// <param name="context"></param> protected override void Execute(NativeActivityContext context) { //拿到输入参数的值 string bookMarkName = context.GetValue(BookMarkName); //创建bookMark,第一个是他的名字,第二个是传递一个委托事件 ,并且唤醒bookMark。 //以下等同于,第一个参数是名字,第二个参数是一个方法。 context.CreateBookmark(bookMarkName, ExecuteContinue); } protected override bool CanInduceIdle { get { return true; } } /// <summary> /// 当下次唤起BookMark,那么该方法被执行. /// </summary> /// <param name="context"></param> /// <param name="bookmark"></param> /// <param name="value"></param> public void ExecuteContinue(NativeActivityContext context, Bookmark bookmark, object value) { int i = Convert.ToInt32(value); context.SetValue(ReturnResult,i); } } }