我們都知道對於一個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 }
這時,產生了工作流中一個重要的內容------書簽(BookMark)
場景:在實際業務場景中,流程一般都是復雜的,不會一口氣從開始走到最后,當在某一個需要暫停的時候,這時,書簽很好的充當了這個使者,就好像我們平時看書,看到某一頁突然有事要離開,但辦完事回來還是要接着看的對不對,通常我們會在暫停的位置放置一個標簽,等我們下次繼續翻閱,可以很快的知道上一次暫停的位置。
步驟:
1.在項目中添加一個代碼活動(CodeActivity),
【注意】
- 將繼承的CodeActivity父類改成NativeActivity,
- 同時將Execute方法中的參數也要修改為NatveActivityContext
- 重寫父類的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)); } } }
操作結果:
點擊提交申請
點擊第一個審批(因為我在流程圖那邊設置了當天數<6時,經理審批同意后直接結束)
別急,做到這里,也只是完成了三分之一,因為你會發現當你點擊提交申請,這時,關閉整個應用程序,當你下次訪問,點擊審批的時候,會報錯,
這是為什么呢?因為你點擊提交申請后退出,這時整個WorkFlowApplication對象也會被銷毀,那么問題來了,如何做到工作流實例的具體化?
方案有很多種,你可以采用xml文件保存,也可以把它保存到數據庫,而我將采取后面那種方式,那么你又會說了,數據庫我該怎么設計,別擔心,微軟已經幫我們寫好了SQL腳本,你只需要找到它們並執行一下就好了。
步驟:
步驟:
- 建立數據表
在C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en中可以找到兩個微軟寫好的數據庫腳本
然后數據庫中先執行后者腳本,在執行前者腳本
將工作流對象往數據庫中存儲
引入命名空間:
using System.Activities.DurableInstancing;
using System.Runtime.DurableInstancing;
- 什么時候持久化工作流對象?
在工作流創建之后,為工作流對象注冊一個事件:
wfapp.PersistableIdle += a => { return PersistableIdleAction.Unload; };
- 創建一個SqlWorkFlowInstanceStore對象
SqlWorkflowInstanceStore ss = new SqlWorkflowInstanceStore("server=.;daabase=WorkFlow;uid=sa;pwd=123;");
關聯持久化的工作流對象和具體的存儲實例
wfapp.InstanceStore = ss;
- 如何從數據庫中加載未完成的工作流實例
創建一個存儲實例對象和一個工作流對象,並將它們進行關聯,
注意:重新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); } } }
效果圖:
你會發現在你的數據庫表中多了一條記錄,這時記錄了你上一次未完成的操作(把這個Guid復制下來,放到按鈕1審批的代碼中Load方法中)因為是做測試用
第二次在運行,直接點擊經理審批對應的審批按鈕,你會發現:
同時數據庫中的記錄也不見了
好了,具體實現就這么多了,但是還存在一個問題,那就是對於某個按鈕事件,你會發現重復性的代碼太多了,不妨就自己去進行封裝吧!做成一個屬於自己的Helper!
最后,非常希望大家可以提出批評和建議。謝謝!