Using Workflow Markup

Windows Workflow Foundation gives designers and developers a declarative way to create workflows by using eXtensible Application Markup Language (XAML) to create markup source files. These markup files can be compiled into a workflow type, loaded directly into the workflow runtime engine at run time, or they can be compiled into a workflow type with code-beside files implemented in either C# or Visual Basic. This means that the workflow markup files can be compiled or not, depending on business reasons and whether additional implementation logic is required. The use of workflow markup with code-beside logic files is similar to how ASP.NET separates presentation files from logic files.

For an example of how to load a workflow markup file directly into the workflow run-time engine, see the Running Workflows section of the Creating a Workflow Host Application topic or Using Custom Activities with Workflow Markup.

Basic structure

The basic structure of the workflow markup contains the root node, which denotes the type of workflow, followed by the child activities in that workflow as nested sub elements. Because workflow markup is based on a subset of XAML elements and attributes, the structure of workflow markup files looks similar to that of an XAML file. For example, each element in the workflow is represented as nodes of either composite activities or the workflow itself. The relationship between nodes is preserved just like it is when you create workflows through a programming language such as C# or Visual Basic.

Elements and Attributes

As stated previously, each element in a workflow markup file corresponds to a workflow component. The names for those elements are the same names for the activity types that are used when you create workflows programmatically. For example, the IfElseActivity activity is represented by the <IfElseActivity> element. This is also true for custom activities.

Activity members are declared as shown in the following example. In this example, a DelayActivity activity is configured with a Name of delayActivity1, a TimeoutDuration of fifteen seconds, and the InitializeTimeoutDuration event is set to a method in the code-beside named SetTimeoutDuration.

<DelayActivity
    x:Name="delayActivity1"
    TimeoutDuration="00:00:15" 
    InitializeTimeoutDuration="SetTimeoutDuration" />

XAML also provides the ability to insert procedural code within a workflow markup file using the x:Code directive element. The code must be placed in a CDATA section so that the compiler can compile the code instead of treating it like declarative XAML markup. The following example shows how that element is used with a CDATA section.

<CodeActivity x:Name="codeActivity1" ExecuteCode="methodName1">
  <x:Code><![CDATA[
      void methodName1(object sender, EventArgs e) 
      {
      }
  ]]></x:Code>
</CodeActivity>

Note

The x:Code directive element can only be used in workflow markup files that are compiled.

The following table describes the common attributes of workflow markup.

Attribute Description

x:Array

An array of types.

x:Class

Name of the workflow class including the namespace. The class with this name is created when the workflow is compiled.

x:Name

Name of an activity. Corresponds to the Activity.Name property.

x:Type

A type reference.

x:Null

A null value.

xmlns:x

The namespace for the XAML schema.

xmlns

The namespace for the workflow XAML schema.

Note

If you use a non-compiled, XAML-only workflow markup file to create a workflow, x:Class attribute should not be present in the XAML file. This attribute is valid only when the workflow is being compiled.

Note

If the Root Namespace for a Visual Basic application is changed after a workflow markup file is created, the x:Class attribute of that workflow must also be updated.

Example

The following is an example of a workflow markup file for a compiled workflow and the code-beside file that contains implementation logic for the various event handlers in the workflow.

<SequentialWorkflowActivity
    x:Class="XamlCodeExamples.SampleWorkflow"
    x:Name="SampleWorkflow"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/workflow">
    <CodeActivity x:Name="GenerateRandomNumber"
        ExecuteCode="GenerateRandomNumber_ExecuteCode" />
    <IfElseActivity x:Name="ifElseActivity1">
        <IfElseBranchActivity x:Name="ifElseBranchActivity1">
            <IfElseBranchActivity.Condition>
                <CodeCondition Condition="SampleCodeCondition" />
            </IfElseBranchActivity.Condition>
           <CodeActivity x:Name="EvenNumber" ExecuteCode="EvenNumber_ExecuteCode" />
        </IfElseBranchActivity>
        <IfElseBranchActivity x:Name="ifElseBranchActivity2">
            <CodeActivity x:Name="OddNumber" ExecuteCode="OddNumber_ExecuteCode" />
        </IfElseBranchActivity>
    </IfElseActivity>
</SequentialWorkflowActivity>
public partial class SampleWorkflow : SequentialWorkflowActivity
{
    public int RandomInt { get; set; }

    private void GenerateRandomNumber_ExecuteCode(object sender, EventArgs e)
    {
        RandomInt = new Random().Next(1, 101);
    }

    private void SampleCodeCondition(object sender, ConditionalEventArgs e)
    {
        e.Result = RandomInt % 2 == 0;
    }
    
    private void EvenNumber_ExecuteCode(object sender, EventArgs e)
    {
        Console.WriteLine("{0} is even.", RandomInt);
    }

    private void OddNumber_ExecuteCode(object sender, EventArgs e)
    {
        Console.WriteLine("{0} is odd.", RandomInt);
    }
}

If you use a non-compiled, XAML-only workflow markup file to create a workflow, you must use the ActivityBind markup extension to set all dependency properties of type event handler or they are not called during runtime. One way to accomplish this is to define a custom type that serves as the root workflow element and bind to methods in this custom type. In the following example, the custom workflow type WorkflowBase has a method that matches the signature of a dependency event handler.

public partial class BaseWorkflow : SequentialWorkflowActivity
{
    public BaseWorkflow()
    {
        InitializeComponent();
    }

    public void ExecuteCodeEventHandler(object sender, EventArgs e)
    {
        Console.WriteLine("Base Workflow event handler");
    }
}

The following workflow markup is an example of a workflow of type BaseWorkflow from the previous example that has one CodeActivity activity that has its ExecuteCode dependency event bound to the ExecuteCodeEventHandler method that is defined in BaseWorkflow.

<?xml version="1.0" encoding="utf-16"?>
<ns0:BaseWorkflow x:Name="BaseWorkflow"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/workflow" 
    xmlns:x="http://sch//emas.microsoft.com/winfx/2006/xaml" 
    xmlns:ns0="clr-namespace:XamlCodeExamples;Assembly=XamlCodeExamples, 
    Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        <CodeActivity
            x:Name="codeActivity1"
            ExecuteCode="{ActivityBind BaseWorkflow,Path=ExecuteCodeEventHandler}"
        />
</ns0:BaseWorkflow>

Note

The previous example shows how to use a CodeActivity in a markup-only workflow but you can use this technique for any activity that has dependency events.

See Also

Reference

System.Windows.Markup

Concepts

Using Custom Activities with Workflow Markup
Using Rules with Workflow Markup
How to: Serialize Workflows
Serialization Overview

Other Resources

Markup Samples
Developing Workflows