Dynamically Invoking SharePoint Designer Workflow
Hi,
Is it possible to provide workflow type forInvokeWorkflowActivity dynamically?
i.e., I'd like to use theInvokeWorkflowActivity in other workflow, but exact type of workflow is not known in design time.
Thanks,
Mark
There is no way to do this with the out of the box InvokeWorkflowActivity.The TargetWorkflow property is a metadata property. Metadata properties must be set at design time and can’t be updated at runtime.However, you can create your own custom activity like the following which should get you started:
using System;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Drawing.Design;
using System.Collections.Generic;
namespace ActivityLibrary1
{
public partial class CustomInvokeWorkflowActivity : Activity, ITypeFilterProvider
{
public static readonly DependencyProperty TargetWorkflowProperty = DependencyProperty.Register("TargetWorkflow", typeof(Type), typeof(CustomInvokeWorkflowActivity), new PropertyMetadata(null));
public static readonly DependencyProperty ParameterBindingsProperty = DependencyProperty.Register("ParameterBindings", typeof(WorkflowParameterBindingCollection), typeof(CustomInvokeWorkflowActivity), new PropertyMetadata(DependencyPropertyOptions.ReadOnly, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content) }));
public CustomInvokeWorkflowActivity()
{
base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
InitializeComponent();
}
#region Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// CustomInvokeWorkflowActivity
//
this.Name = "CustomInvokeWorkflowActivity";
}
#endregion
[Category("Activity")]
[Description("Type of workflow to invoke")]
[Editor(typeof(TypeBrowserEditor), typeof(UITypeEditor))]
[DefaultValue(null)]
public Type TargetWorkflow
{
get
{
return base.GetValue(TargetWorkflowProperty) as Type;
}
set
{
base.SetValue(TargetWorkflowProperty, value);
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Browsable(false)]
public WorkflowParameterBindingCollection ParameterBindings
{
get
{
return base.GetValue(ParameterBindingsProperty) as WorkflowParameterBindingCollection;
}
}
#region ITypeFilterProvider Members
bool ITypeFilterProvider.CanFilterType(Type type, bool throwOnError)
{
bool canFilterType = TypeProvider.IsAssignable(typeof(Activity), type) && type != typeof(Activity) && !type.IsAbstract;
if (throwOnError && !canFilterType)
throw new Exception("Type does not derive from Activity");
return canFilterType;
}
string ITypeFilterProvider.FilterDescription
{
get
{
return "Select a Type that derives from Activity.";
}
}
#endregion
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (this.TargetWorkflow == null)
{
throw new InvalidOperationException("TargetWorkflow property must be set to a valid Type that derives from Activity.");
}
Dictionary<string, object> parameters = new Dictionary<string, object>();
foreach (WorkflowParameterBinding parameterBinding in this.ParameterBindings)
parameters.Add(parameterBinding.ParameterName, parameterBinding.Value);
(executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow).StartWorkflow(this.TargetWorkflow, parameters);
return ActivityExecutionStatus.Closed;
}
}
}
IStartWorkflow.StartWorkflow returns the InstanceId for the invoked workflow.In the example I ignore the return value but you could make the following changes.
Add the following property:
public static readonly DependencyProperty InstanceIdProperty = DependencyProperty.Register("InstanceId", typeof(Guid), typeof(CustomInvokeWorkflowActivity));
[Category("Activity")]
[Description("InstanceId of workflow that is invoked")]
public Guid InstanceId
{
get
{
return (Guid)base.GetValue(InstanceIdProperty);
}
set
{
base.SetValue(InstanceIdProperty, value);
}
}
Update the StartWorkflow line in the Execute method to:
base.SetValue(InstanceIdProperty, (executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow).StartWorkflow(this.TargetWorkflow, parameters));
Now you can bind the property to a variable and you are able to use the InstanceId later in the workflow if you need to.