Introduction
This blog post will show you how to start a workflow programmatically every time an item is updated in a SharePoint list. For those who don’t know, Windows Workflow Foundation (WF) is the new engine for building custom workflows (you can find more information about WF on the official web site). It was released as part of the .NET Framework 3.0 along with Windows Presentation Foundation (WPF) and Windows Communication Foundation (WCF). In the SharePoint world, workflows can be associated both to a list and to a content type. Both options are valid and the choice for one or the other option depends on your needs:
- If you want to run a workflow in a list, independently of the content type of each list item, you should associate the workflow to a list. If you have more than one content type associated to the list, care should be taken in the workflow implementation since each content type can have different columns that may not be present in the other content types;
- If you want to run the workflow on all items of a specific content type, you should associate the workflow to a content type. The workflow will be associated to all list items from that content type in all lists across a site or the whole site collection (depending on the scope of the workflow, typically defined in its deployment feature) that are associated with the content type.
Example
The following example shows how both options can be addressed. This example uses an event handler and starts a workflow every time an item is updated in a SharePoint list.
public class ProgrammaticWorkflowInitiationEventReceiver : SPItemEventReceiver
{
/// <summary>
/// Event handler for item updated event.
/// </summary>
/// <param name="properties"></param>
public override void ItemUpdated(SPItemEventProperties properties)
{
//use this method if the workflow is associated to a list
StartListWorkflow(properties);
//use this method if the workflow is associated to a content type
StartContentTypeWorkflow(properties);
}
/// <summary>
/// Starts a workflow associated to a list programmatically.
/// </summary>
/// <param name="properties"></param>
private void StartListWorkflow(SPItemEventProperties properties)
{
//get list item from event handler properties
SPListItem listItem = properties.ListItem;
using (SPWeb web = listItem.Web)
{
using (SPSite site = web.Site)
{
//obtain an instance of SPWorkflowManager
//which will be later used to start the workflow
SPWorkflowManager manager = site.WorkflowManager;
//get item's parent list
SPList parentList = listItem.ParentList;
//get all workflows that are associated with the list
SPWorkflowAssociationCollection associationCollection =
parentList.WorkflowAssociations;
//lookup and start the worflow
LookupAndStartWorkflow(listItem, manager,
associationCollection, "MyListWorkflow");
}
}
}
/// <summary>
/// Starts a workflow associated to a content type programmatically.
/// </summary>
/// <param name="properties"></param>
private void StartContentTypeWorkflow(SPItemEventProperties properties)
{
//get list item from event handler properties
SPListItem listItem = properties.ListItem;
using (SPWeb web = listItem.Web)
{
using (SPSite site = web.Site)
{
//obtain an instance of SPWorkflowManager
//which will be later used to start the workflow
SPWorkflowManager manager = site.WorkflowManager;
//get item's content type
SPContentType contentType = listItem.ContentType;
//get all workflows that are associated with the content type
SPWorkflowAssociationCollection associationCollection =
contentType.WorkflowAssociations;
//lookup and start the worflow
LookupAndStartWorkflow(listItem, manager,
associationCollection, "MyContentTypeWorkflow");
}
}
}
/// <summary>
/// Lookup and start the workflow.
/// </summary>
/// <param name="manager"></param>
/// <param name="associationCollection"></param>
/// <param name="workflowInstanceName"></param>
private static void LookupAndStartWorkflow(SPListItem listItem,
SPWorkflowManager manager,
SPWorkflowAssociationCollection associationCollection,
string workflowInstanceName)
{
//iterate workflow associations and lookup the workflow to be started
foreach (SPWorkflowAssociation association in associationCollection)
{
//if the workflow association matches the workflow we are looking for,
//get its association data and start the workflow
if (association.Name.ToLower().Equals(workflowInstanceName))
{
//get workflow association data
string data = association.AssociationData;
//start workflow
SPWorkflow wf = manager.StartWorkflow(listItem, association, data);
}
}
}
}
In the previous example, the following actions are being performed:
- The ItemUpdated event in the event handler is being handled. For demonstration purposes, I am assuming that two workflow associations were created, one to the list (named "MyListWorkflow") and another to a content type (named "MyContentTypeWorkflow");
- A call is made to the StartListWorkflow method, which starts the workflow associated with a list;
- A call is made to the StartContentTypeWorkflow method, which starts the workflow associated with a content type.