DynamicActivity Creation

This topic applies to Windows Workflow Foundation 4 (WF4).

This sample demonstrates two different ways to create an activity at runtime using the DynamicActivity activity.

In this sample, an activity is created at runtime with a body that contains a Sequence activity that contains ForEach and Assign activities. An input list of integers is passed into the activity and set as a property. The ForEach activity then iterates over the list of values and accumulates it. In the Assign activity, the average value is calculated by dividing the accumulator by the number of elements in the list and assign it to the average.

The sample demonstrates the usage of a DynamicActivity activity that flows in variables as input arguments and returning values as output arguments. The activity has one input argument named Numbers that is a list of integers. The ForEach activity iterates over the list of values and accumulates it. In the Assign activity, the average value is calculated by dividing the accumulator by the number of elements in the list and assigning it to the average. The average is returned as an output argument named Average.

When the dynamic activity is created programmatically, the input and output are declared as shown in the following code example.

DynamicActivity act = new DynamicActivity()
{
    DisplayName = "Find average",
    Properties = 
    {
        // Input argument
        new DynamicActivityProperty
        {
            Name = "Numbers",
            Type = typeof(InArgument<List<int>>),
            Value = numbers
        },
        // Output argument
        new DynamicActivityProperty
        {
            Name = "Average",
            Type = typeof(OutArgument<double>),
            Value = average
        }
    },
};

The following code example shows the complete definition of the DynamicActivity that computes the average of the values in a list.

DynamicActivity act = new DynamicActivity()
{
    DisplayName = "Find average",
    Properties = 
    {
        // Input argument
        new DynamicActivityProperty
        {
            Name = "Numbers",
            Type = typeof(InArgument<List<int>>),
            Value = numbers
        },
        // Output argument
        new DynamicActivityProperty
        {
            Name = "Average",
            Type = typeof(OutArgument<double>),
            Value = average
        }
    },
    Implementation = () =>
        new Sequence
        {
            Variables = { result, accumulator },
            Activities =
            {
                new ForEach<int>
                {
                    Values =  new ArgumentValue<IEnumerable<int>> { ArgumentName = "Numbers" },                                
                    Body = new ActivityAction<int>
                    {
                        Argument = iterationVariable,
                        Handler = new Assign<int>
                        {
                            To = accumulator,
                            Value = new InArgument<int>(env => iterationVariable.Get(env) +  accumulator.Get(env))
                        }
                    }
                },

                // Calculate the average and assign to the output argument.
                new Assign<double>
                {
                    To = new ArgumentReference<double> { ArgumentName = "Average" },
                    Value = new InArgument<double>(env => accumulator.Get(env) / numbers.Get(env).Count<int>())
                },
            }
        }
};

When created in XAML, the input and output are declared as shown in the following example.

<Activity x:Class="Microsoft.Samples.DynamicActivityCreation.FindAverage"
          xmlns="https://schemas.microsoft.com/netfx/2009/xaml/activities"
          xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib"
          xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
  <x:Members>
    <x:Property Name="Numbers" Type="InArgument(scg:List(x:Int32))" />
    <x:Property Name="Average" Type="OutArgument(x:Double)" />
  </x:Members>
    ...
    ...
</Activity>

The XAML can be created visually using the Windows Workflow Designer. If it is included in a Visual Studio project, be sure to set its “Build Action” to “None” to prevent it from being compiled. The XAML can then be loaded dynamically using the following call.

Activity act2 = ActivityXamlServices.Load(@"FindAverage.xaml");

The DynamicActivity instance created programmatically or through loading a XAML workflow can be used as shown in the following code example. Please note that “act” passed to the WorkflowInvoker.Invoke is the “act” Activity defined in the first code example.

IDictionary<string, object> results = WorkflowInvoker.Invoke(act, new Dictionary<string, object> { { "Numbers", numbers } });

Console.WriteLine("The average calculated using the code activity is = " + results["Average"]);

To use this sample

  1. Using Visual Studio 2010, open the DynamicActivityCreation.sln solution file.

  2. To build the solution, press CTRL+SHIFT+B.

  3. To run the solution, press CTRL+F5.

Command line arguments

This sample accepts command line arguments. Users can provide a list of numbers for the activity to calculate their average. The list of numbers to be used is passed as a list of numbers separated by a space. For example, to calculate the average of 5, 10, and 32 invoke the sample using the following command line.

DynamicActivityCreation 5 10 32
Dd807392.Important(en-us,VS.100).gif Note:
The samples may already be installed on your machine. Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WF samples. This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WF\Basic\Built-InActivities\DynamicActivity\DynamicActivityCreation