Monday, December 9, 2013

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 (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

a. Creating a custom content type.

Add custom fields to the content type: RequestMessage, ApprovalStatus, ReassignTaskTo, RequestChangeFrom, NewRequest, and DelegatedBy.

Also change the form url in <FormUrls><Display> and <FormUrls><Edit> to WorkflowForms/TaskForm.aspx, later we will talk about this custom task edit form.

Following is the Elements.xml:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Parent ContentType: Task (0x0108) -->
<Field ID="{512503F1-C067-464E-8C7A-6B915E54C378}" Name="RequestMessage" DisplayName="Request Message" Description=""
Direction="None" Type="Note" Overwrite="TRUE"
xmlns="http://schemas.microsoft.com/sharepoint/" />
<Field ID="{517B22A5-1B89-4C24-82BE-3D4FD99645BC}" Name="ApprovalStatus" MaxLength="255" DisplayName="Approval Status" Description="" Direction="None" Type="Text" Overwrite="TRUE"
xmlns="http://schemas.microsoft.com/sharepoint/" />
<Field ID="{0EBA7379-141A-4941-9E46-3DE750D84553}" Name="ReassignTaskTo" MaxLength="255" DisplayName="Reassign Task To" Description="" Direction="None" Type="Text" Overwrite="TRUE"
xmlns="http://schemas.microsoft.com/sharepoint/" />
<Field ID="{8D7CD395-204D-4E4D-BAFF-FFE2FC3C4C3E}" Name="RequestChangeFrom" MaxLength="255" DisplayName="Request Change From" Description="" Direction="None" Type="Text" Overwrite="TRUE"
xmlns="http://schemas.microsoft.com/sharepoint/" />
<Field ID="{FDA85E0C-B29C-4C59-9DE2-5D3FE74240FD}" Name="NewRequest" MaxLength="255" DisplayName="New Request" Description="" Direction="None" Type="Text" Overwrite="TRUE"
xmlns="http://schemas.microsoft.com/sharepoint/" />
<Field ID="{7F0DA0FA-C12F-415F-A990-99BC011CD34B}" Name="DelegatedBy" MaxLength="255" DisplayName="Delegated By" Description="" Direction="None" Type="Text" Overwrite="TRUE"
xmlns="http://schemas.microsoft.com/sharepoint/" />

<ContentType ID="0x0108010035c1f8f76b7a41458bcc4ee62c6a332e"
Name="myWorkflowContentType" Group="Custom Content Types"
Description="My Content Type" Version="0">
<FieldRefs>
<FieldRef ID="{512503F1-C067-464E-8C7A-6B915E54C378}" Name="RequestMessage" DisplayName="Request Message" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
<FieldRef ID="{517B22A5-1B89-4C24-82BE-3D4FD99645BC}" Name="ApprovalStatus" DisplayName="Approval Status" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
<FieldRef ID="{0EBA7379-141A-4941-9E46-3DE750D84553}" Name="ReassignTaskTo" DisplayName="Reassign Task To" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
<FieldRef ID="{8D7CD395-204D-4E4D-BAFF-FFE2FC3C4C3E}" Name="RequestChangeFrom" DisplayName="Request Change From" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
<FieldRef ID="{FDA85E0C-B29C-4C59-9DE2-5D3FE74240FD}" Name="NewRequest" DisplayName="New Request" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
<FieldRef ID="{7F0DA0FA-C12F-415F-A990-99BC011CD34B}" Name="DelegatedBy" DisplayName="Delegated By" Required="FALSE" Hidden="FALSE" ReadOnly="FALSE" PITarget="" PrimaryPITarget="" PIAttribute="" PrimaryPIAttribute="" Aggregation="" Node="" />
</FieldRefs>
<XmlDocuments>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<Display>ListForm</Display>
<Edit>ListForm</Edit>
<New>ListForm</New>
</FormTemplates>
</XmlDocument>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
<FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
<Display>WorkflowForms/TaskForm.aspx</Display>
<Edit>WorkflowForms/TaskForm.aspx</Edit>
</FormUrls>
</XmlDocument>
</XmlDocuments>
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
</ContentType>
</Elements>

Please see: Creating a custom sequential workflow similar with SharePoint OOTB Approval workflow (2) Custom Activity, While Activity and Replicator Activity.
In this article, there is a custom activity, the activity class declared many properties such as TaskTitle , TaskDescription , RequestMessage, ApprovalStatus, DelegatedBy, NewRequest, …, they are passed in/out from/to outside parent activity. We also need to pass these fields in/out from/to task edit form by the custom fields included in this content type.
For example, in createSPTaskWithContentType activity, we pass RequestMessage, DelegatedBy and NewRequest to the content type fields(included in the task list item) by following code:

SPTaskProperties.ExtendedProperties[RequestMessageGuid] = ((SPTaskActivity)((Activity)sender).Parent).RequestMessage;
SPTaskProperties.ExtendedProperties[DelegatedByGuid] = ((SPTaskActivity)((Activity)sender).Parent).DelegatedBy;
SPTaskProperties.ExtendedProperties[NewRequestGuid] = ((SPTaskActivity)((Activity)sender).Parent).NewRequest;

These data will be picked up in task edit form.
The ContentType ID starts with 0x010801, which means this content type is derived from Workflow Task.
This ContentType ID is assigned to the task ContentTypeId in createSPTaskWithContentType activity.
Set this content type as a site collection feature.

b. Being able to associate workflow with any tasks list.

In this workflow’s association form, work on the code behind file.
Create a method AddContentTypeToTaskList() as following:

private void AddContentTypeToTaskList()
{
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        Web.AllowUnsafeUpdates = true;
        SPContentType TestDataCT = Web.AvailableContentTypes["myWorkflowContentType"];
        SPList TaskList = Web.Lists[(this.associationParams.TaskListGuid)];
        SPContentType ExistCT = TaskList.ContentTypes["myWorkflowContentType"];
        if (ExistCT == null)
        {
            TaskList.ContentTypesEnabled = true;
            TaskList.Update();
            TaskList.ContentTypes.Add(TestDataCT);
            TaskList.Update();
            SPContentTypeCollection listCTs = TaskList.ContentTypes;
            System.Collections.Generic.List<SPContentType> result = new System.Collections.Generic.List<SPContentType>();
            foreach (SPContentType ct in listCTs)
            {
                if (ct.Name.Contains("myWorkflowContentType"))
                {
                    result.Add(ct);
                }
            }
            TaskList.RootFolder.UniqueContentTypeOrder = result;
            TaskList.RootFolder.Update();
        }
    });
}

Add it to Associate Workflow button click event handler, the code looks like following:

protected void AssociateWorkflow_Click(object sender, EventArgs e)
{
    // Optionally, add code here to perform additional steps before associating your workflow
    try
    {
        CreateTaskList();
        CreateHistoryList();
        HandleAssociateWorkflow();
        AddContentTypeToTaskList(); SPUtility.Redirect("WrkSetng.aspx", SPRedirectFlags.RelativeToLayoutsPage, HttpContext.Current, Page.ClientQueryString);
    }
    catch (Exception ex)
    {
        SPUtility.TransferToErrorPage(String.Format(CultureInfo.CurrentCulture, workflowAssociationFailed, ex.Message));
    }
}

When user selects any task list or a new task list in association form, and click Associate Workflow button, myWorkflowContentType will be assigned to this task list.

c. Applying custom task edit form.

Create a custom task edit form, see this article: Walkthrough: Creating a simple Sequential Workflow with a custom Task Form in SharePoint 2010 using Visual Studio 2010 (Part 1 of 2).
In this task edit form’s page load event, get all the necessary data by this code: SPListItem item = SPContext.Current.ListItem, this is the task list item, the custom Content Type myWorkflowContentType is included in this item.
add code to display different task information according to it is for approval or change request.
Following is the code for button Approve, Reject and Cancel:

protected void btnApprove_Click(object sender, EventArgs e)
{
    SPList l = SPContext.Current.List;
    SPListItem li = SPContext.Current.ListItem;
    li[SPBuiltInFieldId.TaskStatus] = "Completed";
    li[SPBuiltInFieldId.PercentComplete] = 1;
    li["ApprovalStatus"] = "1";
    SaveButton.SaveItem(SPContext.Current, false, "");
    CloseForm();
}

protected void btnReject_Click(object sender, EventArgs e)
{
    SPList l = SPContext.Current.List;
    SPListItem li = SPContext.Current.ListItem;
    li[SPBuiltInFieldId.TaskStatus] = "Completed";
    li[SPBuiltInFieldId.PercentComplete] = 1;
    li["ApprovalStatus"] = "2";
    SaveButton.SaveItem(SPContext.Current, false, "");
    CloseForm();
}

protected void btnCancel_Click(object sender, EventArgs e)
{
    CloseForm();
}

The code for button Reassign Task and Change Request will be shown later when we talk about the topic.

No comments:

Post a Comment