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
Concepts
Using Custom Activities with Workflow Markup
Using Rules with Workflow Markup
How to: Serialize Workflows
Serialization Overview