How to launch a workflow on more than one list item simultaneously


A very common question that pops up during my training sessions is how does one automatically launch a workflow instance on a list item.

To do this, first and foremost create a Custom Action and display it on the Ribbon. The following xml added to an Empty Element in a SharePoint Project will give us the Custom Action.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <CustomAction Id="ScriptSource1"
                  ScriptSrc="Workflows/RibbonActionCommands.js"
                  Location="ScriptLink"
                  Sequence="100">
    </CustomAction>

    <CustomAction Id="StartWorkflowAction"
                  Location="CommandUI.Ribbon"
                  RegistrationType="List"                  
                  RegistrationId="101">
        <CommandUIExtension>
            <CommandUIDefinitions>
                <CommandUIDefinition Location="Ribbon.Documents.Workflow.Controls._children">
                    <Button Id="StartWorkflowButton1"
                            Image16by16="/_layouts/Images/Workflows/Check_16x16.png"
                            Image32by32="/_layouts/Images/Workflows/Check_32x32.png"
                            LabelText="Start Approval Workflow"
                            Command="StartWorkflowCommand"
                            Sequence="10000"
                            TemplateAlias="o1"/>
                </CommandUIDefinition>
            </CommandUIDefinitions>
            <CommandUIHandlers>
                <CommandUIHandler Command="StartWorkflowCommand"
                                  CommandAction="javascript:RedirectToWorkflowLaunchPage('{SiteUrl}', '{ListId}')"
                                  EnabledScript="javascript:CheckSelectedItems()">                    
                </CommandUIHandler>
            </CommandUIHandlers>
        </CommandUIExtension>
    </CustomAction>                  
</Elements>

Add the Layouts mapped folder to the solution and in it, add a JS file (named RibbonActionCommands.js in this example) which will hold the JavaScript code for the Ribbon Button. Add another application page called “WorkflowLauncher.aspx” which will contain the C# code to programmatically launch a workflow on the selected list items.

image

In the RibbonActionCommands.js file, add the following JavaScript code –

function RedirectToWorkflowLaunchPage(siteurl, listid) {
    //Some feedback to the user, while we re-direct to the application page.
    SP.UI.Notify.addNotification('Redirecting...');

    //Get a list of all the selected items (the items on which the workflow is supposed to run)
    var items = SP.ListOperation.Selection.getSelectedItems();

    //Iterate thru the array of selected items and create a comma seperated string consisting of all the selected item ids.
    var selecteditems = "";
    for (i in items) {        
        selecteditems += items[i].id + ",";
    }

    //strip out the last ','
    selecteditems = selecteditems.substr(0,selecteditems.length-1);

    //redirect the user to a dummy aspx page.
    //We pass the id of the list and the selected items in the querystring to the page
    window.location = siteurl + "/_layouts/Workflows/workflowlauncher.aspx?listid=" + listid + "&itemids=" + selecteditems;
}

function CheckSelectedItems() {
    //This function checks if more than one list item has been selected; only then does it return true. 
    //As long as this function returns false, the Ribbon Button will remain disabled.
    var items = SP.ListOperation.Selection.getSelectedItems();
    return items.length >= 1;
}
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <asp:Label runat="server" ID="lblStatus"></asp:Label>
</asp:Content>

In the code behind file, add the following code in the Page Load event handler

        protected void Page_Load(object sender, EventArgs e)
        {
            string listid = Request.QueryString["listid"].ToString();
            string itemids = Request.QueryString["itemids"].ToString();
            string[] ids = itemids.Split(',');

            //starting a workflow on list items will involve updating some infomation in the Content DBs.
            //Since these updates will be happening in response to an HTTP GET request, they will be disallowed by default
            SPContext.Current.Web.AllowUnsafeUpdates = true;

            //get a reference to the list            
            SPList list = SPContext.Current.Web.Lists[new Guid(listid)];

            //get a reference to the workflow we want to start. 
            //In this example, we assume that the workflow we need to start is named 'Approval'
            SPWorkflowAssociationCollection workflows = list.WorkflowAssociations;
            SPWorkflowAssociation association = null;
            foreach (SPWorkflowAssociation item in workflows)
            {
                if (item.Name == "Approval")
                    association = item;                
            }

            //We couldn't find a workflow named 'Approval' associated with the list/library
            if (association == null)
                lblStatus.Text = "<h3>There is no workflow named 'Approval' associated with this Library</h3>";
            else
            {
                //Start long operation
                SPLongOperation op = new SPLongOperation(this.Page);
                op.LeadingHTML = "Please wait while the Approval workflow starts on the selected items";
                op.Begin();

                using (var manager = SPContext.Current.Site.WorkflowManager)
                {                    
                    foreach (string id in ids)
                    {
                        //item on which the workflow should run
                        SPListItem item = list.Items.GetItemById(Int32.Parse(id));

                        //start workflow and pass anything you want to it, or in this case null
                        manager.StartWorkflow(item, association, association.AssociationData);
                    }
                }

                //End Long operation
                op.End(list.DefaultViewUrl);
            }
            SPContext.Current.Web.AllowUnsafeUpdates = false;                
        }

Since initiating a workflow on multiple list items could potentially take a long time to complete, we use the SPLongOperation class to delimit that operation. As a result, the user sees the following familiar page that SharePoint always pulls up whenever a long running operation is in progress.

image

The end result is that the Approval workflow automatically starts running on all the selected items

image

Advertisements

One Response to How to launch a workflow on more than one list item simultaneously

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: