一、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);
}
}
}