使用命令式程式碼撰寫工作流程
本主題僅適用於 Windows Workflow Foundation 4。
工作流程定義是配置之活動物件的樹狀結構。有很多方式可定義這個活動的樹狀結構,包含手動編輯 XAML 或使用工作流程設計工具來產生 XAML。不過,XAML 並非必要條件。您也可以程式設計的方式建立工作流程定義。本主題會提供使用程式碼建立工作流程定義的概觀。
建立工作流程定義
具現化活動型別的執行個體,並設定活動物件的屬性,即可建立工作流程定義。對於不包含任何子活動的活動,這個部分僅需使用幾行程式碼便能完成。
Activity wf = new WriteLine
{
Text = "Hello World."
};
WorkflowInvoker.Invoke(wf);
![]() |
---|
本主題中的範例使用 WorkflowInvoker 來執行簡易的工作流程。如需詳細資訊叫用工作流程、傳遞引數以及可用的不同裝載選項的詳細資訊,請參閱使用 WorkflowInvoker 與 WorkflowApplication。 |
在這個範例中,會建立由單一 WriteLine 活動構成的工作流程。WriteLine 活動的 Text 引數會進行設定,並叫用工作流程。如果活動包含子活動,則建構方式會相當類似。下列範例會使用包含兩個 WriteLine 活動的 Sequence 活動。
Activity wf = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Hello"
},
new WriteLine
{
Text = "World."
}
}
};
WorkflowInvoker.Invoke(wf);
使用物件初始設定式
本主題的範例會使用物件初始化語法。物件初始化語法在使用程式碼建立工作流程定義時會很有用,因為它會在工作流程中提供活動的階層式檢視,並顯示活動之間的關係。當您以程式設計方式來建立工作流程時,不一定非得使用物件初始化語法。下列範例在功能上等同於先前的範例。
WriteLine hello = new WriteLine();
hello.Text = "Hello";
WriteLine world = new WriteLine();
world.Text = "World";
Sequence wf = new Sequence();
wf.Activities.Add(hello);
wf.Activities.Add(world);
WorkflowInvoker.Invoke(wf);
如需詳細資訊物件初始設定式的詳細資訊,請參閱 HOW TO:初始化物件但不呼叫建構函式 (C# 程式設計手冊) 與 HOW TO:使用物件初始設定式宣告物件。
處理變數、常值和運算式
使用程式碼建立工作流程定義時,請注意哪個程式碼是做為建立工作流程定義的一部分,以及哪個程式碼是做為該工作流程執行個體的一部分執行。例如,下列工作流程目的是要產生隨機號碼,並將它寫入主控台。
Variable<int> n = new Variable<int>
{
Name = "n"
};
Activity wf = new Sequence
{
Variables = { n },
Activities =
{
new Assign<int>
{
To = n,
Value = new Random().Next(1, 101)
},
new WriteLine
{
Text = new InArgument<string>((env) => "The number is " + n.Get(env))
}
}
};
當執行此工作流程定義程式碼時,會呼叫 Random.Next
,且會將結果儲存於工作流程定義做為常值。此工作流程的許多執行個體都可加以叫用,且所有的執行個體都會顯示相同的號碼。若要在工作流程執行期間產生隨機號碼,必須使用每當工作流程執行時所計算的運算式。
new Assign<int>
{
To = n,
Value = new VisualBasicValue<int>("New Random().Next(1, 101)")
}
VisualBasicValue 是以 Visual Basic 語法表示的運算式,可用來當做運算式中的右值 (r-value),且每當執行內含的活動時會進行計算。運算式的結果會指派至工作流程變數 n
,且會由工作流程中的下一個活動使用這些結果。若要在執行階段時存取工作流程變數 n
的值,必須要有 ActivityContext。這可以使用下列 Lambda 運算式來進行存取。
new WriteLine
{
Text = new InArgument<string>((env) => "The number is " + n.Get(env))
}
Lambda 運算式不可序列化為 XAML 格式。若要讓此運算式相容於 XAML,請使用 ExpressionServices 與 Convert,如下列範例所示。
new WriteLine
{
//Text = new InArgument<string>((env) => "The number is " + n.Get(env))
Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
}
也可以使用 VisualBasicValue。
new WriteLine
{
//Text = new InArgument<string>((env) => "The number is " + n.Get(env))
//Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
Text = new VisualBasicValue<string>("\"The number is \" + n.ToString()")
}
如需詳細資訊如需運算式的詳細資訊,請參閱運算式。
引數與動態活動
工作流程定義是在程式碼中藉由組裝活動至活動樹狀目錄,並設定任何屬性與引數所建立。可繫結現有的引數,但無法新增新引數至活動。這包含傳遞至根活動的工作流程引數。在命令式程式碼中,會將工作流程引數指定為新 CLR 型別的屬性,並且在 XAML 中使用 x:Class 與 x:Member 來宣告它們。因為將工作流程定義建立為記憶體內物件的樹狀結構時,並未建立任何新 CLR 型別,所以無法新增引數。但是,可新增引數至 DynamicActivity。在此範例中會建立 DynamicActivity,它採用兩個整數引數並將其同時加入,然後傳回結果。不僅會針對每個引數建立 DynamicActivityProperty,且會將作業的結果指派至 DynamicActivity 的 Result 引數。
InArgument<int> Operand1 = new InArgument<int>();
InArgument<int> Operand2 = new InArgument<int>();
DynamicActivity<int> wf = new DynamicActivity<int>
{
Properties =
{
new DynamicActivityProperty
{
Name = "Operand1",
Type = typeof(InArgument<int>),
Value = Operand1
},
new DynamicActivityProperty
{
Name = "Operand2",
Type = typeof(InArgument<int>),
Value = Operand2
}
},
Implementation = () => new Sequence
{
Activities =
{
new Assign<int>
{
To = new ArgumentReference<int> { ArgumentName = "Result" },
Value = new InArgument<int>((env) => Operand1.Get(env) + Operand2.Get(env))
}
}
}
};
Dictionary<string, object> wfParams = new Dictionary<string, object>
{
{ "Operand1", 25 },
{ "Operand2", 15 }
};
int result = WorkflowInvoker.Invoke(wf, wfParams);
Console.WriteLine(result);
如需詳細資訊如需動態活動的詳細資訊,請參閱使用 DynamicActivity 在執行階段建立活動。