序列化工作流程及 XAML 之間的活動
本主題僅適用於 Windows Workflow Foundation 4。
除了將工作流程定義編譯成包含在組件中的類型之外,工作流程定義也可以序列化為 XAML。這些序列化的定義可重新載入以供編輯或檢閱、傳遞至建置系統以進行編譯,或載入及叫用。本主題提供序列化工作流程定義以及使用 XAML 工作流程定義的概觀。
使用 XAML 工作流程定義
若要建立要序列化的工作流程定義,請使用 ActivityBuilder 類別。建立 ActivityBuilder 與建立 DynamicActivity 十分類似。您要指定任何所需的引數,以及設定構成行為的活動。在下列範例中,會建立 Add
活動,它接受兩個輸入引數、加總這些引數,然後傳回結果。因為這個活動會傳回結果,所以要使用泛型 ActivityBuilder 類別。
ActivityBuilder<int> ab = new ActivityBuilder<int>();
ab.Name = "Add";
ab.Properties.Add(new DynamicActivityProperty { Name = "Operand1", Type = typeof(InArgument<int>) });
ab.Properties.Add(new DynamicActivityProperty { Name = "Operand2", Type = typeof(InArgument<int>) });
ab.Implementation = new Sequence
{
Activities =
{
new WriteLine
{
Text = new VisualBasicValue<string>
{
ExpressionText= "Operand1.ToString() + \" + \" + Operand2.ToString()"
},
},
new Assign<int>
{
To = new ArgumentReference<int> { ArgumentName = "Result" },
Value = new VisualBasicValue<int>
{
ExpressionText = "Operand1 + Operand2"
}
}
}
};
每個 DynamicActivityProperty 執行個體代表工作流程的一個輸入引數,而 Implementation 包含形成工作流程邏輯的活動。
若要將 ActivityBuilder 執行個體所代表的工作流程定義序列化為 XAML,請使用 ActivityXamlServices 建立 XamlWriter,然後透過 XamlWriter 使用 XamlServices 序列化工作流程定義。ActivityXamlServices 有方法,可用來在 XAML 中來回對應 ActivityBuilder 執行個體,以及載入 XAML 工作流程並傳回可叫用的 DynamicActivity。在下列範例中,會將上一個範例的 ActivityBuilder 執行個體序列化為字串,然後儲存至檔案。
// Serialize the workflow to XAML and store it in a string.
StringBuilder sb = new StringBuilder();
StringWriter tw = new StringWriter(sb);
XamlWriter xw = ActivityXamlServices.CreateBuilderWriter(new XamlXmlWriter(tw, new XamlSchemaContext()));
XamlServices.Save(xw , ab);
string serializedAB = sb.ToString();
// Display the XAML to the console.
Console.WriteLine(serializedAB);
// Serialize the workflow to XAML and save it to a file.
StreamWriter sw = File.CreateText(@"C:\Workflows\add.xaml");
XamlWriter xw2 = ActivityXamlServices.CreateBuilderWriter(new XamlXmlWriter(sw, new XamlSchemaContext()));
XamlServices.Save(xw2, ab);
sw.Close();
下列範例代表序列化的工作流程。
<Activity
x:TypeArguments="x:Int32"
x:Class="Add"
xmlns="https://schemas.microsoft.com/netfx/2009/xaml/activities"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<x:Members>
<x:Property Name="Operand1" Type="InArgument(x:Int32)" />
<x:Property Name="Operand2" Type="InArgument(x:Int32)" />
</x:Members>
<Sequence>
<WriteLine Text="[Operand1.ToString() + " + " + Operand2.ToString()]" />
<Assign x:TypeArguments="x:Int32" Value="[Operand1 + Operand2]">
<Assign.To>
<OutArgument x:TypeArguments="x:Int32">
<ArgumentReference x:TypeArguments="x:Int32" ArgumentName="Result" />
</OutArgument>
</Assign.To>
</Assign>
</Sequence>
</Activity>
若要載入序列化的工作流程,請使用 ActivityXamlServices Load 方法。這個方法接受序列化的工作流程定義,並傳回代表工作流程定義的 DynamicActivity。請注意,等到驗證程序期間呼叫 DynamicActivity 主體上的 CacheMetadata 時,XAML 才會還原序列化。如果未明確呼叫驗證,則會在叫用工作流程時執行驗證。如果 XAML 工作流程定義無效,則會擲回 Argument 例外狀況。從 CacheMetadata 擲回的任何例外狀況會從 Validate 呼叫中逸出,而且必須由呼叫端處理。在下列範例中,會載入上一個範例的序列化工作流程,並透過 WorkflowInvoker 叫用它。
// Load the workflow definition from XAML and invoke it.
DynamicActivity<int> wf = ActivityXamlServices.Load(new StringReader(serializedAB)) as DynamicActivity<int>;
Dictionary<string, object> wfParams = new Dictionary<string, object>
{
{ "Operand1", 25 },
{ "Operand2", 15 }
};
int result = WorkflowInvoker.Invoke(wf, wfParams);
Console.WriteLine(result);
當叫用這個工作流程時,主控台就會顯示下列輸出。
25 + 15
40
注意: |
---|
如需詳細資訊以輸入和輸出引數叫用工作流程的詳細資訊,請參閱使用 WorkflowInvoker 與 WorkflowApplication 和 Invoke。 |
序列化的工作流程定義也可以透過 ActivityXamlServices CreateBuilderReader 方法載入至 ActivityBuilder 執行個體。在序列化的工作流程載入至 ActivityBuilder 執行個體之後,可對它進行檢查和修改。對自訂工作流程設計工具作者來說,這項功能很實用,在設計過程中提供了儲存及重新載入工作流程定義的機制。在下列範例中,會載入上一個範例的序列化工作流程定義,並檢查其屬性。
// Create a new ActivityBuilder and initialize it using the serialized
// workflow definition.
ActivityBuilder<int> ab2 = XamlServices.Load(
ActivityXamlServices.CreateBuilderReader(
new XamlXmlReader(new StringReader(serializedAB)))) as ActivityBuilder<int>;
// Now you can continue working with the ActivityBuilder, inspect
// properties, etc...
Console.WriteLine("There are {0} arguments in the activity builder.", ab2.Properties.Count);