Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

SharePoint 2010 State Machine Workflows with Custom Task Forms (InfoPath) using VS 2010 - Part 1 of 3

, 3 Dec 2012
A tutorial on SharePoint 2010 Custom State Machine Workflows with Custom Task forms in InfoPath 2010. An example based tutorial, where I simulate the Recruitment Process of an organization.
RecruitmentProcess-noexe.zip
RecruitmentProcess
RecruitmentProcess.suo
RecruitmentProcess
bin
Release
RecruitmentProcess.wsp
Features
Feature1
Feature1.feature
key.snk
obj
Release
Package
Package.package
pkg
Debug
RecruitmentProcess
RecruitmentProcess_Feature1
Forms
InitialClearancePublish.xsn
TechnicalClearancePublish.xsn
RecruitmentWorkflow
Release
RecruitmentProcess
RecruitmentProcess_Feature1
Forms
InitialClearancePublish.xsn
TechnicalClearancePublish.xsn
RecruitmentWorkflow
pkgobj
Release
TokenReplaceFolder
RecruitmentProcess_Feature1
Forms
RecruitmentWorkflow
Properties
RecruitmentProcess.csproj.user
RecruitmentWorkflow
Forms
InitialClearancePublish.xsn
SharePointProjectItem.spdata
TechnicalClearancePublish.xsn
RecruitmentWorkflow.layout
SharePointProjectItem.spdata
Workflow.png
recruitmentprocess.zip
RecruitmentProcess.suo
Debug
Microsoft.Sharepoint.Sandbox.dll
RecruitmentProcess.dll
RecruitmentProcess.pdb
RecruitmentProcess.wsp
Feature1.feature
key.snk
Debug
TempPE
DesignTimeResolveAssemblyReferences.cache
DesignTimeResolveAssemblyReferencesInput.cache
RecruitmentProcess.dll
RecruitmentProcess.pdb
ResolveAssemblyReference.cache
TempPE
Package.package
RecruitmentProcess.dll
InitialClearancePublish.xsn
TechnicalClearancePublish.xsn
RecruitmentProcess.dll
InitialClearancePublish.xsn
TechnicalClearancePublish.xsn
RecruitmentProcess.csproj.user
InitialClearancePublish.xsn
SharePointProjectItem.spdata
TechnicalClearancePublish.xsn
RecruitmentWorkflow.layout
SharePointProjectItem.spdata
Workflow.png
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;

namespace RecruitmentProcess
{
    public sealed partial class RecruitmentWorkflow : StateMachineWorkflowActivity
    {
        public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();

        public Guid createTaskInitialClearanceTaskId = default(System.Guid);
        public SPWorkflowTaskProperties createTaskInitialClearanceTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedInitialClearanceBeforeProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedInitialClearanceAfterProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        public Guid createTaskTechnicalClearanceTaskId = default(System.Guid);
        public SPWorkflowTaskProperties createTaskTechnicalClearanceTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedTechnicalClearanceAfterProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedTechnicalClearanceBeforeProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        public Guid createTaskHRClearanceTaskId = default(System.Guid);
        public SPWorkflowTaskProperties createTaskHRClearanceTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedHRClearanceAfterProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedHRClearanceBeforeProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        public Guid createTaskAcceptedTaskId = default(System.Guid);
        public SPWorkflowTaskProperties createTaskAcceptedTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedAcceptedAfterProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedAcceptedBeforeProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        public Guid createTaskRejectedTaskId = default(System.Guid);
        public SPWorkflowTaskProperties createTaskRejectedTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedRejectedAfterProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
        public SPWorkflowTaskProperties onTaskChangedRejectedBeforeProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

        public RecruitmentWorkflow()
        {
            InitializeComponent();
        }

        #region Workflow Activated

        private void onWorkflowActivatedInitial_Invoked(object sender, ExternalDataEventArgs e)
        {

        }

        #endregion Workflow Activated

        #region Initial Clearance

        private void createTaskInitialClearance_MethodInvoking(object sender, EventArgs e)
        {
            try
            {
                //Create a new TaskId for the Task
                this.createTaskInitialClearanceTaskId = Guid.NewGuid();

                //TaskProperties field is used to configure the Task Details.
                this.createTaskInitialClearanceTaskProperties.Title = "Initial Clearance";
                //You can assign a Task to an user or to a group. Here we assign the task to HR-Group
                this.createTaskInitialClearanceTaskProperties.AssignedTo = @"Trigyn\Rupesh.Tarwade";

                SPListItem listItem = this.workflowProperties.Item;
                this.createTaskInitialClearanceTaskProperties.ExtendedProperties["ows_title"] = SharePointHelper.GetFieldValue(listItem, "Title");
                this.createTaskInitialClearanceTaskProperties.ExtendedProperties["ows_technology"] = SharePointHelper.GetFieldValue(listItem, "Technology");
                this.createTaskInitialClearanceTaskProperties.ExtendedProperties["ows_experience"] = SharePointHelper.GetFieldValue(listItem, "Experience");

                //Task Type corresponds to TaskURN specified in Elements.xml
                this.createTaskInitialClearanceTaskProperties.TaskType = 1;

                this.createTaskInitialClearanceTaskProperties.DueDate = DateTime.Today.AddDays(5.0);
            }
            catch (Exception ex)
            {
                //Logging is used so that we can debug the errors in the workflow.
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
            }
        }

        private void onTaskChangedInitialClearance_Invoked(object sender, ExternalDataEventArgs e)
        {
            try
            {
                this.onTaskChangedInitialClearanceAfterProperties = this.onTaskChangedInitialClearance.AfterProperties;
                this.onTaskChangedInitialClearanceBeforeProperties = this.onTaskChangedInitialClearance.BeforeProperties;

                //Set the PercentComplete property to 1.0 (i.e. 100%) to indicate that the task has been completed.
                this.onTaskChangedInitialClearanceAfterProperties.PercentComplete = (float)1.0;

                //Get the value of Remarks Column (InfoPath Form) by using the ExtendedProperties property
                string remarks = this.onTaskChangedInitialClearanceBeforeProperties.ExtendedProperties["Remarks"].ToString();

                SPListItem listItem = this.workflowProperties.Item;

                //Write the remarks value to the list item
                if (listItem != null && listItem.Fields.ContainsField("InitialRemarks"))
                {
                    listItem["InitialRemarks"] = remarks;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
                //throw ex;
            }
        }

        private void InitialClearanceApprovalProcess(object sender, ConditionalEventArgs e)
        {
            try
            {
                //if (this.onTaskChangedInitialClearanceAfterProperties.PercentComplete == (float)1.0 && 
                //   this.onTaskChangedInitialClearanceAfterProperties.ExtendedProperties["Status"] != null &&
                //   this.onTaskChangedInitialClearanceAfterProperties.ExtendedProperties["Status"].ToString().Contains("Approved"))
                //{
                e.Result = true;
                //}
                //else
                //{
                //   e.Result = false;
                //}
            }
            catch (Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
            }
        }

        #endregion Initial Clearance

        #region Technical Clearance

        private void createTaskTechnicalClearance_MethodInvoking(object sender, EventArgs e)
        {
            try
            {
                //Create a new TaskId for the Task
                this.createTaskTechnicalClearanceTaskId = Guid.NewGuid();

                //TaskProperties field is used to configure the Task Details.
                this.createTaskTechnicalClearanceTaskProperties.Title = "Technical Clearance";

                //You can assign a Task to an user or to a group. Here we assign the task to HR-Group

                SPListItem listItem = this.workflowProperties.Item;
                //Write the remarks value to the list item
                if (listItem != null)
                {
                    //Check if TechnicalInterviewAssignedTo Field has a value, and Assign this Task to the value of this Field
                    //if (listItem.Fields.ContainsField("TechnicalInterviewAssignedTo"))
                    //{
                    //   this.createTaskTechnicalClearanceTaskProperties.AssignedTo = listItem["TechnicalInterviewAssignedTo"].ToString();
                    //}

                    this.createTaskTechnicalClearanceTaskProperties.AssignedTo = @"Trigyn\Rupesh.Tarwade";

                    //To send InitialRemarks to the InfoPath Form, we add it to the ExtendedProperty of the TaskProperties
                    //ExtendedProperties is a hashtable (Key-Value pair). 
                    //The Key will be the name of field we have used in ItemMetaData.xml and Value will be the value of remarks
                    if (listItem.Fields.ContainsField("InitialRemarks"))
                    {
                        if (this.createTaskTechnicalClearanceTaskProperties.ExtendedProperties.ContainsKey("InitialComments"))
                        {
                            this.createTaskTechnicalClearanceTaskProperties.ExtendedProperties["InitialComments"] = listItem["InitialRemarks"].ToString();
                        }
                        else
                        {
                            this.createTaskTechnicalClearanceTaskProperties.ExtendedProperties.Add("InitialComments", listItem["InitialRemarks"].ToString());
                        }
                    }
                }

                //Task Type corresponds to TaskURN specified in Elements.xml
                this.createTaskTechnicalClearanceTaskProperties.TaskType = 2;

                this.createTaskTechnicalClearanceTaskProperties.DueDate = DateTime.Today.AddDays(2.0);
            }
            catch (Exception ex)
            {
                //Logging is used so that we can debug the errors in the workflow.
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
            }
        }

        private void onTaskChangedTechnicalClearance_Invoked(object sender, ExternalDataEventArgs e)
        {
            try
            {
                this.onTaskChangedTechnicalClearanceAfterProperties = this.onTaskChangedTechnicalClearance.AfterProperties;
                this.onTaskChangedTechnicalClearanceBeforeProperties = this.onTaskChangedTechnicalClearance.BeforeProperties;

                //Set the PercentComplete property to 1.0 (i.e. 100%) to indicate that the task has been completed.
                this.onTaskChangedTechnicalClearanceAfterProperties.PercentComplete = (float)1.0;

                //Get the value of Remarks Column (InfoPath Form) by using the ExtendedProperties property
                string remarks = this.onTaskChangedTechnicalClearanceBeforeProperties.ExtendedProperties["Remarks"].ToString();

                SPListItem listItem = this.workflowProperties.Item;

                //Write the remarks value to the list item
                if (listItem != null && listItem.Fields.ContainsField("TechnicalInterviewRemarks"))
                {
                    listItem["TechnicalInterviewRemarks"] = remarks;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
                //throw ex;
            }
        }

        private void TechnicalClearanceApprovalProcess(object sender, ConditionalEventArgs e)
        {
            try
            {
                //if (this.onTaskChangedTechnicalClearanceAfterProperties.PercentComplete == (float)1.0 && this.onTaskChangedTechnicalClearanceAfterProperties.ExtendedProperties["Status"].ToString().Contains("Approved"))
                //{
                e.Result = true;
                //}
                //else
                //{
                //   e.Result = false;
                //}
            }
            catch (Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
            }
        }

        #endregion Technical Clearance

        #region HR Clearance

        private void createTaskHRClearance_MethodInvoking(object sender, EventArgs e)
        {
            try
            {
                //Create a new TaskId for the Task
                this.createTaskInitialClearanceTaskId = Guid.NewGuid();

                //TaskProperties field is used to configure the Task Details.
                this.createTaskInitialClearanceTaskProperties.Title = "Initial Clearance";
                //You can assign a Task to an user or to a group. Here we assign the task to HR-Group
                this.createTaskInitialClearanceTaskProperties.AssignedTo = @"Trigyn\Rupesh.Tarwade";

                //Task Type corresponds to TaskURN specified in Elements.xml
                this.createTaskInitialClearanceTaskProperties.TaskType = 2;

                this.createTaskInitialClearanceTaskProperties.DueDate = DateTime.Today.AddDays(5.0);
            }
            catch (Exception ex)
            {
                //Logging is used so that we can debug the errors in the workflow.
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
            }
        }

        private void onTaskChangedHRClearance_Invoked(object sender, ExternalDataEventArgs e)
        {
            try
            {
                this.onTaskChangedHRClearanceAfterProperties = this.onTaskChangedHRClearance.AfterProperties;
                this.onTaskChangedHRClearanceBeforeProperties = this.onTaskChangedHRClearance.BeforeProperties;

                //Set the PercentComplete property to 1.0 (i.e. 100%) to indicate that the task has been completed.
                this.onTaskChangedHRClearanceAfterProperties.PercentComplete = (float)1.0;

                //Get the value of Remarks Column (InfoPath Form) by using the ExtendedProperties property
                string remarks = this.onTaskChangedHRClearanceBeforeProperties.ExtendedProperties["Remarks"].ToString();

                SPListItem listItem = this.workflowProperties.Item;

                //Write the remarks value to the list item
                if (listItem != null && listItem.Fields.ContainsField("HRRemarks"))
                {
                    listItem["HRRemarks"] = remarks;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow", ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
                LogToHistoryListActivity log = new LogToHistoryListActivity();
                log.HistoryDescription = ex.StackTrace;
                //throw ex;
            }
        }

        private void HRClearanceApprovalProcess(object sender, ConditionalEventArgs e)
        {
            e.Result = true;
        }

        #endregion HR Clearance

        #region Accepted

        private void createTaskAccepted_MethodInvoking(object sender, EventArgs e)
        {

        }

        private void onTaskChangedAccepted_Invoked(object sender, ExternalDataEventArgs e)
        {

        }

        #endregion Accepted

        #region Rejected

        private void createTaskRejected_MethodInvoking(object sender, EventArgs e)
        {

        }

        private void onTaskChangedRejected_Invoked(object sender, ExternalDataEventArgs e)
        {

        }

        #endregion Rejected
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Rupesh Tarwade
Technical Lead
India India
I have been designing and developing systems in .NET since 2006. Started out with .NET 1.1, and progressed to 2.0, 3.0 and 3.5. I have recently dived into SharePoint 2010 development. My areas of expertise are Workflows in .NET and SharePoint.
Follow on   Twitter   Google+   LinkedIn

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 3 Dec 2012
Article Copyright 2011 by Rupesh Tarwade
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid