Monday, December 2, 2013

Creating a custom sequential workflow similar with SharePoint OOTB Approval workflow (2) Custom Activity, While Activity and Replicator Activity


Creating a custom sequential workflow similar with SharePoint OOTB Approval workflow (1) Association / Initiation Form
Creating a custom sequential workflow similar with SharePoint OOTB Approval workflow (2) Custom Activity, While Activity and Replicator Activity
Creating a custom sequential workflow similar with SharePoint OOTB Approval workflow (3) custom Content Type and custom Task Edit Form
Creating a custom sequential workflow similar with SharePoint OOTB approval workflow (4) End on first rejection
Creating a custom sequential workflow similar with SharePoint OOTB approval workflow (5) cancel task(s) when item changed
Creating a custom sequential workflow similar with SharePoint OOTB approval workflow (6) reassign task and request change

To create a workflow dynamically handling multiple stages for multiple approvers in parallel mode or serial mode, we do following steps:

a.     Creating a custom activity
Create a new Class File and Inherit System.Workflow.Activities.SequenceActivity, then we will have the designer UI and name it SPTaskActivity, place CreateTaskWithContentType, OnTaskChanged and CompleteTask activities.
We will create a custom task edit form and some custom fields in the tasks list for approval later, so we use CreateTaskWithContentType instead of CreateTask. We will talk about this topic later on.




Set CorrelationToken as "taskToken" and OwnerActivityName as “SPTaskActivity”.
In order to allow properties to be passed in/out from/to outside parent activity, we need to declare necessary properties. Following is the code snippet:


using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel.Design;

namespace SPTaskActivity
{
    public partial class SPTaskActivity : SequenceActivity
    {
           public string TaskTitle { get; set; }
         public string TaskDescription { get; set; }
           public string TaskAssignedTo { get; set; }
         public string RequestMessage { get; set; }
              ……

After completing the coding on each activity, build the application. Now a new custom activity will be available in your toolbox.

b.     Creating a workflow
Now go back to the project and create a workflow, add activities like following, drag the SPTaskActivity from your toolbox and drop it inside your replicateTasks.


From previous article, Creating a custom workflow similar with SharePoint OOTB Approval workflow (1) Association Form / Initiation Form, we have the stages data in workflow’s stages IList, every item is a string of users login name separated by comma, the last letter of this string is a letter “P” or “S” also separated by comma indicating this stage is in parallel mode or serial mode.

The whileActivity1 in workflow diagram is for stages.
Set the Condition property to Code Condition, and specify following method:

private void notComplete(object sender, ConditionalEventArgs e)
            {
                assignees = new ArrayList();
                if ((i_while < stages.Count) && Approved)
                {
                    string[] uids = stages[i_while].ToString().Split(',');
                    ArrayList _AssignTo = new ArrayList();
                    _AssignTo.AddRange(uids);
                    _AssignTo.RemoveAt(_AssignTo.Count - 1);
                    ArrayList _AssignToUsers = CommonUtilities.UserList(_AssignTo, workflowProperties.Web);
                    if (_AssignToUsers.Count > 0)
                    {
                        for (int i = 0; i < _AssignToUsers.Count; i++)
                        {
                            assignees.Add(_AssignToUsers[i].ToString());
                        }
                        replicateTasks.InitialChildData = assignees;
                        if (uids[uids.Length - 1] == "P")
                        {
                            replicateTasks.ExecutionType = ExecutionType.Parallel;
                        }
                        else
                        {
                            replicateTasks.ExecutionType = ExecutionType.Sequence;
                        }
                    }
                    e.Result = !complete;
                }
                else
                {
                    e.Result = complete;
                }
                i_while = i_while + 1;
            }

In above code, replicateTasks is assigned with approvers in each stages, and replicateTasks.ExecutionType is ExecutionType.Parallel or ExecutionType.Sequence depending on the last letter of the string.
The initial value of i_while is 0, CommonUtilities.UserList() is a method to pick up every single user if the entity is a SharePoint group. _AssignTo.RemoveAt(_AssignTo.Count - 1) is to remove the last letter of this string (“P” or “S”);
Boolean variable Approved is used to stop the process if any approval task is rejected.

The replicateActivity1 in workflow diagram is for approvers in serial and parallel mode.

    private void replicatorActivity1_Initialized(object sender, EventArgs e)
    {
        if (assignees.Count > 0)
        {
            spTaskActivity1.TaskAssignedTo = assignees[assignees.Count - 1].ToString();
            spTaskActivity1.TaskTitle = WorkflowConst.TaskTitle + workflowProperties.Item.Title;
            spTaskActivity1.TaskDescription = WorkflowConst.TaskDescription;
            spTaskActivity1.ApprovalStatus = "0";
            spTaskActivity1.RequestMessage = RequestMessage;
        }
    }

    private void replicatorActivity1_ChildInitialized(object sender,  ReplicatorChildEventArgs e)
    {
        ((SPTaskActivity.SPTaskActivity)e.Activity).TaskAssignedTo = e.InstanceData.ToString();
        ((SPTaskActivity.SPTaskActivity)e.Activity).TaskTitle = WorkflowConst.TaskTitle + workflowProperties.Item.Title;
        ((SPTaskActivity.SPTaskActivity)e.Activity).TaskDescription = WorkflowConst.TaskDescription;
        ((SPTaskActivity.SPTaskActivity)e.Activity).ApprovalStatus = "0";
        SPRegionalSettings oRegionalSettings = workflowProperties.Web.RegionalSettings;
        SPTimeZone oTimeZone = oRegionalSettings.TimeZone;
        ((SPTaskActivity.SPTaskActivity)e.Activity).RequestMessage = WorkflowConst.ApprovalStartedBy + workflowProperties.OriginatorUser.Name + WorkflowConst.On + oTimeZone.UTCToLocalTime(workflowProperties.Workflow.Created).ToString() + " Comment: " + RequestMessage;
    }
The custom activity is wrapped in two level loops, While Activity and Replicator Activity, this is Spawned Contexts. So we need to use the event parameter to reference the custom activity properties to pass parameters.





No comments:

Post a Comment