Sam
Sam

Reputation: 133

InvokeWorkflow activity inside a replicator activity

I have an invokeworkflow activity inside a replicator activity. The workflow that I'm trying to invoke requires 2 parameters to be passed to it, an integer and a string parameters, and these should be passed to the workflow by the replicator activity. Any ideas on how this could be done?

Thanks.

Upvotes: 0

Views: 2831

Answers (3)

Panos
Panos

Reputation: 19142

You can declare two properties in the target workflow like this:

    public static readonly DependencyProperty MyIntProperty =
        DependencyProperty.Register("MyInt", typeof(int), typeof(Workflow3));
    public static readonly DependencyProperty MyStringProperty =
        DependencyProperty.Register("MyString", typeof(string), typeof(Workflow3));

    public int MyInt
    {
        get { return (int)GetValue(MyIntProperty); }
        set { SetValue(MyIntProperty, value); }
    }

    public string MyString
    {
        get { return (string)GetValue(MyStringProperty); }
        set { SetValue(MyStringProperty, value); }
    }

After that, if you check the Properties tab of the InvokeWorkflowActivity you will see the two properties in the Parameters category.

You can either provide constant values or you can bind them to any property of the hosting workflow.

Upvotes: 0

WalterG
WalterG

Reputation: 11

I realize this post is old, but for those finding this on Google with the same question, this is what you need to do:

  1. Wrap the call to InvokeWorkflow in a custom Activity - this will simplify mapping the parameters. In this Activity create a DependencyProperty for each of the properties you want to pass to the invoked workflow. Let's call this our "InvokerActivity" for now. Then in the InvokeWorkflowActivity, map the properties of the TargetWorkflow to the dependency properties on the InvokerActivity, as Panos suggests above. NOTE: in order for the ellipsis to show up the objects MUST be concrete types. If your object is an Interface you will not be able to map it. The workflow will not know how to instantiate an interface object.
  2. Place the InvokerActivity inside the ReplicatorActivity, using the designer.
  3. The ReplicatorActivity exposes an event handler called ChildInitialized. Create your handler for this event and in it you will receive a ReplicatorChildEventArgs. In it, you can receive the Activity through the event args as such:

        InvokerActivity activity = (e.Activity as InvokerActivity);
        if (activity != null)
        {
            activity.MyParam = e.InstanceData as MyParamType;
        }
    

Now when you run it, the ReplicatorActivity will call this method once for every item in the collection and will pass along the parameters for each of the InvokerActivities it will spawn.

e.InstanceData will be the next object in the collection that the Replicator is iterating through.

Upvotes: 1

Panos
Panos

Reputation: 19142

Here is a full example (note that whatever is included in the constructors can be set in the properties pane of the designer): Workflow3 is the target workflow that contains only a CodeActivity and the behind code is the following:

public sealed partial class Workflow3 : SequentialWorkflowActivity
{
    public static readonly DependencyProperty MyIntProperty =
        DependencyProperty.Register("MyInt", typeof(int), typeof(Workflow3));
    public static readonly DependencyProperty MyStringProperty =
        DependencyProperty.Register("MyString", typeof(string), typeof(Workflow3));

    public Workflow3()
    {
        InitializeComponent();

        this.codeActivity1.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode);
    }

    public int MyInt
    {
        get { return (int)GetValue(MyIntProperty); }
        set { SetValue(MyIntProperty, value); }
    }

    public string MyString
    {
        get { return (string)GetValue(MyStringProperty); }
        set { SetValue(MyStringProperty, value); }
    }

    private void codeActivity1_ExecuteCode(object sender, EventArgs e)
    {
        Console.WriteLine("Invoke WF: Int = {0}, String = {1}", this.MyInt, this.MyString);
    }
}

Workflow2 is the hosting workflow that contains only a ReplicatorActivity. The ReplicatorActivity contains only a InvokeWorkflowActivity which has the TargetWorkflow set to Workflow3. The code-behind is the following:

public sealed partial class Workflow2 : SequentialWorkflowActivity
{
    // Variables used in bindings
    public int InvokeWorkflowActivity1_MyInt = default(int);
    public string InvokeWorkflowActivity1_MyString = string.Empty;

    public Workflow2()
    {
        InitializeComponent();

        // Bind MyInt parameter of target workflow to my InvokeWorkflowActivity1_MyInt
        WorkflowParameterBinding wpb1 = new WorkflowParameterBinding("MyInt");
        wpb1.SetBinding(WorkflowParameterBinding.ValueProperty, new ActivityBind(this.GetType().Name, "InvokeWorkflowActivity1_MyInt"));
        this.invokeWorkflowActivity1.ParameterBindings.Add(wpb1);

        // Bind MyString parameter of target workflow to my InvokeWorkflowActivity1_MyString
        WorkflowParameterBinding wpb2 = new WorkflowParameterBinding("MyString");
        wpb2.SetBinding(WorkflowParameterBinding.ValueProperty, new ActivityBind(this.GetType().Name, "InvokeWorkflowActivity1_MyString"));
        this.invokeWorkflowActivity1.ParameterBindings.Add(wpb2);

        // Add event handler for Replicator's Initialized event
        this.replicatorActivity1.Initialized += new EventHandler(ReplicatorInitialized);

        // Add event handler for Replicator's ChildInitialized event
        this.replicatorActivity1.ChildInitialized += new EventHandler<ReplicatorChildEventArgs>(this.ChildInitialized);
    }

    private void ReplicatorInitialized(object sender, EventArgs e)
    {
        // Find how many workflows I want
        List<MyClass> list = new List<MyClass>();
        list.Add(new MyClass() { MyInt = 1, MyString = "Str1" });
        list.Add(new MyClass() { MyInt = 2, MyString = "Str2" });
        list.Add(new MyClass() { MyInt = 3, MyString = "Str3" });

        // Assign list to replicator
        replicatorActivity1.InitialChildData = list;
    }

    private void ChildInitialized(object sender, ReplicatorChildEventArgs e)
    {
        // This is the activity that is initialized
        InvokeWorkflowActivity currentActivity = (InvokeWorkflowActivity)e.Activity;

        // This is the initial data
        MyClass initialData = (MyClass)e.InstanceData;

        // Setting the initial data to the activity
        InvokeWorkflowActivity1_MyInt = initialData.MyInt;
        InvokeWorkflowActivity1_MyString = initialData.MyString;
    }

    public class MyClass
    {
        public int MyInt { get; set; }
        public string MyString { get; set; }
    }
}

The expected outcome is the following:

Invoke WF: Int = 1, String = Str1
Invoke WF: Int = 2, String = Str2
Invoke WF: Int = 3, String = Str3

Hope that this will help you.

Upvotes: 2

Related Questions