作法:執行工作流程
本主題將延續 Windows Workflow Foundation 快速入門教學課程,並討論如何建立工作流程主機以及執行上一個 How to: Create a Workflow 主題中定義的工作流程。
注意
「快速入門」教學課程中的每個主題都與之前的主題息息相關。 若要完成此主題,您必須先完成 How to: Create an Activity 和 How to: Create a Workflow。
建立工作流程主機專案
使用 Visual Studio 2012 開啟前面的如何:建立活動主題中的解決方案。
在 [ 方案總管 ] 中,以滑鼠右鍵按一下 [ WF45GettingStartedTutorial ] 方案,並依序選取 [ 加入]、[ 新增專案]。
提示
如果沒有顯示 [ 方案總管 ] 視窗,請選取 [ 檢視 ] 功能表上的 [ 方案總管 ]。
在 [ 已安裝 ] 節點中,選取 [ Visual C#]、[ 工作流程 ] (或 [ Visual Basic]、[ 工作流程])。
注意
依據設定哪個程式語言為 Visual Studio 主要語言而異,[ Visual C# ] 或 [ Visual Basic ] 節點可能會顯示在 [ 已安裝 ] 節點中的 [ 其他語言 ] 節點下。
確認已選取 [.NET Framework 版本] 下拉式清單中的 [ .NET Framework 4.5 ]。 選取 [ 工作流程 ] 清單中的 [ 工作流程主控台應用程式 ]。 在 [名稱]
NumberGuessWorkflowHost
方塊中輸入 ,然後按一下 [確定] 。 這樣會建立一個具有基本工作流程裝載支援的入門工作流程應用程式。 此基本裝載程式碼會修改,並用來執行工作流程應用程式。在 [ 方案總管 ] 中,以滑鼠右鍵按一下新加入的 [ NumberGuessWorkflowHost ] 專案,然後選取 [ 加入參考]。 選取 [ 加入參考 ] 清單中的 [ 解決方案 ]、勾選 [ NumberGuessWorkflowActivities] 旁的核取方塊,然後按一下 [ 確定]。
在 [ 方案總管 ] 中,以滑鼠右鍵按一下 Workflow1.xaml ,再選擇 [ 刪除]。 按一下 [ 確定 ] 以確認。
修改工作流程裝載程式碼
按兩下 [ 方案總管 ] 中的 [ Program.cs ] 或 [ Module1.vb ],顯示其程式碼。
提示
如果沒有顯示 [ 方案總管 ] 視窗,請選取 [ 檢視 ] 功能表上的 [ 方案總管 ]。
因為這個專案是使用 [ 工作流程主控台應用程式 ] 範本所建立,所以 [ Program.cs ] 或 [ Module1.vb ] 會包含下列基本工作流程裝載程式碼。
' Create and cache the workflow definition. Dim workflow1 As Activity = New Workflow1() WorkflowInvoker.Invoke(workflow1)
// Create and cache the workflow definition. Activity workflow1 = new Workflow1(); WorkflowInvoker.Invoke(workflow1);
這個所產生的裝載程式碼使用 WorkflowInvoker。 WorkflowInvoker 提供一種簡單方法來叫用工作流程,如同方法呼叫一般,但只能用於不使用持續性的工作流程。 WorkflowApplication 提供更豐富的模型,可執行包含生命週期事件通知、執行控制、書籤繼續以及持續性的工作流程。 此範例會使用書籤且將 WorkflowApplication 用於裝載工作流程。 將下列
using
或 Imports 陳述式加入至 Program.cs 或 Module1.vb 上層的現有 using 或 Imports 陳述式下方。Imports NumberGuessWorkflowActivities Imports System.Threading
using NumberGuessWorkflowActivities; using System.Threading;
使用下列基本 WorkflowInvoker 裝載程式碼來取代使用 WorkflowApplication 的程式碼字行。 這個範例裝載程式碼會示範裝載及叫用工作流程的基本步驟,但是尚未包含從這個主題成功執行工作流程的功能。 在下列步驟中,會修改此基本程式碼,並加入其他功能,直到應用程式完成為止。
注意
您必須將這些範例中的
Workflow1
換成FlowchartNumberGuessWorkflow
、SequentialNumberGuessWorkflow
或StateMachineNumberGuessWorkflow
,視您在前面「方法:建立流程」步驟中完成的工作流程而定。 如果您不替換Workflow1
,那麼在您嘗試建置或執行工作流程時,會發生建置錯誤。AutoResetEvent syncEvent = new AutoResetEvent(false); WorkflowApplication wfApp = new WorkflowApplication(_wf); wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e) { syncEvent.Set(); }; wfApp.Aborted = delegate (WorkflowApplicationAbortedEventArgs e) { Console.WriteLine(e.Reason); syncEvent.Set(); }; wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e) { Console.WriteLine(e.UnhandledException.ToString()); return UnhandledExceptionAction.Terminate; }; wfApp.Run(); syncEvent.WaitOne();
Dim syncEvent As New AutoResetEvent(False) Dim wfApp As New WorkflowApplication(New Workflow1()) wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) syncEvent.Set() End Sub wfApp.Aborted = Sub(e As WorkflowApplicationAbortedEventArgs) Console.WriteLine(e.Reason) syncEvent.Set() End Sub wfApp.OnUnhandledException = Function(e As WorkflowApplicationUnhandledExceptionEventArgs) Console.WriteLine(e.UnhandledException) Return UnhandledExceptionAction.Terminate End Function wfApp.Run() syncEvent.WaitOne()
此程式碼會建立 WorkflowApplication、訂閱三個工作流程開發週期事件、使用 Run的呼叫來啟動工作流程,然後等候工作流程完成。 當工作流程完成時,會設定 AutoResetEvent 且主機應用程式會完成。
若要設定工作流程的輸入引數
將下列陳述式加入至 Program.cs 或 Module1.vb 上層的現有
using
或Imports
陳述式下方。以下列用來建立及傳遞參數字典至所建立之工作流程的程式碼,取代建立新 WorkflowApplication 的程式碼字行。
注意
請將這些範例中的
Workflow1
換成FlowchartNumberGuessWorkflow
]、[SequentialNumberGuessWorkflow
或StateMachineNumberGuessWorkflow
,視您在前面 How to: Create a Workflow 步驟中完成的工作流程而定。 如果您不替換Workflow1
,那麼在您嘗試建置或執行工作流程時,會發生建置錯誤。var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
此字典包含具有
MaxNumber
索引鍵的一個項目。 輸入字典中的索引鍵對應至工作流程根活動上的輸入引數。 工作流程會使用MaxNumber
來決定隨機產生的號碼上限。
若要擷取工作流程的輸出引數
修改 Completed 處理常式來擷取與顯示工作流程使用的轉換次數。
Completed = delegate (WorkflowApplicationCompletedEventArgs e) { int Turns = Convert.ToInt32(e.Outputs["Turns"]); Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns); syncEvent.Set(); },
wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns")) Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns) syncEvent.Set() End Sub
若要繼續書籤
將下列程式碼加入至目前
Main
宣告正後方的 AutoResetEvent 方法上方。AutoResetEvent idleEvent = new AutoResetEvent(false);
Dim idleEvent As New AutoResetEvent(False)
將以下的 Idle 處理常式加入至
Main
中現有三個工作流程開發週期處理常式的正下方。Idle = delegate (WorkflowApplicationIdleEventArgs e) { idleEvent.Set(); } };
wfApp.Idle = Sub(e As WorkflowApplicationIdleEventArgs) idleEvent.Set() End Sub
每當工作流程變成閒置狀態,等候下一項猜測值時,就會呼叫此處理常式並設定
idleAction
AutoResetEvent 。 下列步驟中的程式碼會使用idleEvent
和syncEvent
來判斷工作流程是否要等候下一項猜測值或已完成。移除對
WaitOne
的呼叫,並以程式碼取代它來收集來自使用者的輸入,並繼續 Bookmark。移除下列程式碼行。
syncEvent.WaitOne();
syncEvent.WaitOne()
以下列範例取代它。
// Loop until the workflow completes. WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent }; while (WaitHandle.WaitAny(handles) != 0) { // Gather the user input and resume the bookmark. bool validEntry = false; while (!validEntry) { if (!Int32.TryParse(Console.ReadLine(), out int Guess)) { Console.WriteLine("Please enter an integer."); } else { validEntry = true; wfApp.ResumeBookmark("EnterGuess", Guess); } } }
' Loop until the workflow completes. Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent} Do While WaitHandle.WaitAny(waitHandles) <> 0 'Gather the user input and resume the bookmark. Dim validEntry As Boolean = False Do While validEntry = False Dim Guess As Integer If Int32.TryParse(Console.ReadLine(), Guess) = False Then Console.WriteLine("Please enter an integer.") Else validEntry = True wfApp.ResumeBookmark("EnterGuess", Guess) End If Loop Loop
若要建置並執行應用程式
在 [ 方案總管 ] 中,以滑鼠右鍵按一下 [ NumberGuessWorkflowHost ],並選取 [ 設定為啟始專案]。
按 CTRL+F5 建置並執行應用程式。 盡量以最少的次數嘗試猜測數字。
若要以工作流程的其他樣式之一來嘗試使用應用程式,請在用來建立
Workflow1
的程式碼中,將 WorkflowApplication 替換成FlowchartNumberGuessWorkflow
、SequentialNumberGuessWorkflow
或StateMachineNumberGuessWorkflow
,視您想使用的工作流程樣式而定。var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
如需如何將持續性加入工作流程應用程式的指示,請參閱下一個主題: How to: Create and Run a Long Running Workflow。
範例
以下範例是 Main
方法的完整程式碼清單。
注意
請將這些範例中的 Workflow1
換成 FlowchartNumberGuessWorkflow
]、[ SequentialNumberGuessWorkflow
或 StateMachineNumberGuessWorkflow
,視您在前面 How to: Create a Workflow 步驟中完成的工作流程而定。 如果您不替換 Workflow1
,那麼在您嘗試建置或執行工作流程時,會發生建置錯誤。
static void Main(string[] args)
{
AutoResetEvent syncEvent = new AutoResetEvent(false);
AutoResetEvent idleEvent = new AutoResetEvent(false);
var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
WorkflowApplication wfApp = new(_wf, inputs)
{
Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
int Turns = Convert.ToInt32(e.Outputs["Turns"]);
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns);
syncEvent.Set();
},
Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
{
Console.WriteLine(e.Reason);
syncEvent.Set();
},
OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
},
Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
idleEvent.Set();
}
};
wfApp.Run();
// Loop until the workflow completes.
WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent };
while (WaitHandle.WaitAny(handles) != 0)
{
// Gather the user input and resume the bookmark.
bool validEntry = false;
while (!validEntry)
{
if (!Int32.TryParse(Console.ReadLine(), out int Guess))
{
Console.WriteLine("Please enter an integer.");
}
else
{
validEntry = true;
wfApp.ResumeBookmark("EnterGuess", Guess);
}
}
}
}
Sub Main()
Dim syncEvent As New AutoResetEvent(False)
Dim idleEvent As New AutoResetEvent(False)
Dim inputs As New Dictionary(Of String, Object)
inputs.Add("MaxNumber", 100)
Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
wfApp.Completed =
Sub(e As WorkflowApplicationCompletedEventArgs)
Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns"))
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns)
syncEvent.Set()
End Sub
wfApp.Aborted =
Sub(e As WorkflowApplicationAbortedEventArgs)
Console.WriteLine(e.Reason)
syncEvent.Set()
End Sub
wfApp.OnUnhandledException =
Function(e As WorkflowApplicationUnhandledExceptionEventArgs)
Console.WriteLine(e.UnhandledException)
Return UnhandledExceptionAction.Terminate
End Function
wfApp.Idle =
Sub(e As WorkflowApplicationIdleEventArgs)
idleEvent.Set()
End Sub
wfApp.Run()
' Loop until the workflow completes.
Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent}
Do While WaitHandle.WaitAny(waitHandles) <> 0
'Gather the user input and resume the bookmark.
Dim validEntry As Boolean = False
Do While validEntry = False
Dim Guess As Integer
If Int32.TryParse(Console.ReadLine(), Guess) = False Then
Console.WriteLine("Please enter an integer.")
Else
validEntry = True
wfApp.ResumeBookmark("EnterGuess", Guess)
End If
Loop
Loop
End Sub