序列化進出 XAML 的工作流程及活動

除了將工作流程定義編譯成包含在組件中的類型之外,工作流程定義也可以序列化為 XAML。 這些序列化的定義可重新載入以供編輯或檢閱、傳遞至建置系統以進行編譯,或載入及叫用。 本主題提供序列化工作流程定義以及使用 XAML 工作流程定義的概觀。

使用 XAML 工作流程定義

若要建立要序列化的工作流程定義,請使用 ActivityBuilder 類別。 建立 ActivityBuilder 與建立 DynamicActivity 十分類似。 您要指定任何所需的引數,以及設定構成行為的活動。 在下列範例中,會建立 Add 活動,它接受兩個輸入引數、加總這些引數,然後傳回結果。 因為這個活動會傳回結果,所以要使用泛型 ActivityBuilder<TResult> 類別。

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>("Operand1.ToString() + \" + \" + Operand2.ToString()")
        },
        new Assign<int>
        {
            To = new ArgumentReference<int> { ArgumentName = "Result" },
            Value = new VisualBasicValue<int>("Operand1 + Operand2")
        }
    }
};

每個 DynamicActivityProperty 執行個體代表工作流程的一個輸入引數,而 Implementation 包含形成工作流程邏輯的活動。 請注意,此範例中的右值 (r-value) 運算式是 Visual Basic 運算式。 Lambda 運算式不可序列化成 XAML,除非使用 Convert。 如果想要在工作流程設計工具中開啟或編輯序列化的工作流程,則應使用 Visual Basic 運算式。 如需詳細資訊,請參閱使用命令式程式碼撰寫工作流程、活動和運算式

若要將 ActivityBuilder 執行個體代表的工作流程定義序列化為 XAML,請使用 ActivityXamlServices 建立 XamlWriter,然後使用 XamlServices 將工作流程定義序列化 (使用 XamlWriter)。 ActivityXamlServices 包含的方法可雙向對應 ActivityBuilder 執行個體與 XAML,而且可以載入 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="http://schemas.microsoft.com/netfx/2009/xaml/activities"
  xmlns:x="http://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>

若要載入序列化的工作流程,請使用 ActivityXamlServicesLoad 方法。 這個方法接受序列化的工作流程定義,並傳回代表工作流程定義的 DynamicActivity。 請注意,等到驗證程序期間呼叫 CacheMetadata 主體上的 DynamicActivity 時,XAML 才會還原序列化。 如果未明確呼叫驗證,則會在叫用工作流程時執行驗證。 如果 XAML 工作流程定義無效,則會擲回 ArgumentException 例外狀況。 從 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

如果序列化的工作流程包含 C# 運算式,則 ActivityXamlServicesSettings 執行個體 (其 CompileExpressions 屬性已設為 true) 必須以參數形式傳遞至 ActivityXamlServices.Load,否則將擲回 NotSupportedException,並出現類似以下的訊息:運算式活動型別 'CSharpValue`1' 需要編譯才能執行。請確定已編譯工作流程。

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

DynamicActivity<int> wf = ActivityXamlServices.Load(new StringReader(serializedAB), settings) as DynamicActivity<int>;

如需詳細資訊,請參閱 C# 運算式

序列化的工作流程定義也可以透過使用 ActivityXamlServicesCreateBuilderReader 方法,載入至 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);
foreach (var prop in ab2.Properties)
{
    Console.WriteLine("Name: {0}, Type: {1}", prop.Name, prop.Type);
}