Create an InfoPath form to collect specific information for a custom task

In this blog, I will show how to create an InfoPath form that is used by a sequential workflow to capture data as a task to an end user. The workflow we are creating is kicked off OnCreate on a custom list. I won’t get into the details of the list and all the functionality unless it is relevant to what we are trying to demonstrate here. What is important is understanding the basic flow. An item is created on a list, the workflow assigns a task to a user. The task is to provide a score sheet evaluating the data put into the list. We will use an InfoPath 2007 form to capture that data and push the data on submit back to the originating list, not to the task list. Then the workflow can continue on to carry out the rest of the actions necessary.

I started by creating the InfoPath form needed to capture the data that I want pushed back into the list. I am using Visual Studio 2008 to build both the InfoPath form and the workflow. I am using VS2008 rather than VS2010 in order to take advantage of building the InfoPath form in the same solution. This makes it easier to debug. Otherwise, I would definitely recommend using VS2010 instead. (Maybe the subject of another blog Nyah-Nyah)

image

You can see from this form, we are capturing very different from a traditional task. We are going to switch to talking about the workflow. Now that we have the InfoPath form created, we need to create the stub for the submit and give a way to cancel. Add two buttons, one for Submit and one for Cancel. On the cancel button, simply go to the button properties, click on rules, Add, Add Action and select Close the form:

image

For the Submit button it is a little different. We need some code behind to take the data provided by the user and push it back to the list item that originated the workflow. So, right click on the button and select properties. This time, instead of selecting rules, pull down on the Action field and select Submit. The button is now a “known” submit button. Click on Submit Options. I like the form to close after the user has submitted, so click on the Advanced button and check Allow users to submit this form. Then in the after submit field, select the Close the form option. Then click the radio button setting the button to Perform custom action using Code. It should look like the following:

image

Now click on the Edit Code button and it will take you to the code behind in a stubbed out method. This is where you will add code to handle the actual submission. Prior to that though, we need to set some more things up. So, we’ll come back to this. Let’s create the task and then come back to the InfoPath form code.

In my workflow, I added a CreateTask action:

image

Then I set up the TaskProperties and TaskId in the createTask1 properties:

image

Now, let’s get into the code to set the properties for the task being generated. Double click on the createTask1 activity on the workflow designer. This will generate the stub for the invoking method on this activity. From here, we set the TaskId, the fields that need to be populated like Assigned To, Title, DueDate, etc. And then, because we want the InfoPath form to be used instead of the traditional Task form, we tell the task that its task type is 1. I’ll explain this in more detail later on; for now just understand that using the default task form would have a task type = 0, other values point to other forms. We will also need to know the list id from the item that initiated the workflow. We achieve this by pushing the id into an extended property called “ItemId” that we created on the Tasks list. Let’s take a look at the code:

   1: private void createTask1_MethodInvoking(object sender, EventArgs e)

   2: {

   3:     SPListItem item = workflowProperties.Item;

   4:     createTask1.TaskId = Guid.NewGuid();

   5:     SPWorkflowTaskProperties spTaskProperties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();

   6:     // set TaskType = 1 to use the InfoPath form instead of the default task form

   7:     spTaskProperties.TaskType = 1;

   8:     spTaskProperties.AssignedTo = item["Reviewer"].ToString();

   9:     // set the Due Date to one day from assignment

  10:     spTaskProperties.DueDate = DateTime.Now.AddDays(1.0);

  11:     spTaskProperties.Title = "Evaluate Score Sheet for " + this.workflowProperties.Item.Title;

  12:     // later on, we will need a handle to the ListItem that started this workflow

  13:     // so we will copy it to the task in the ItemId field

  14:     spTaskProperties.ExtendedProperties["ItemId"] = item.ID;

  15:     createTask1.TaskProperties = spTaskProperties;

  16: }

Now, let’s get back to the InfoPath code. We need to push data back to a SharePoint list, so make sure that you have a reference to the SharePoint dll. Simply add reference, browse to it by going to C:\Program Files\Common Files\microsoft shared\Web Server Extensions\12\ISAPI and selecting Microsoft.SharePoint.dll. Now we need to get to the OnLoading event on the InfoPath form. To do this, in Visual Studio while looking at the code behind for the InfoPath form, click on the menu item Insert and select Loading Event from the fly-out menu:

image 

That gives you the stub for the loading event on the form. In this event we need to capture the TaskId and the originating ListItemId and push them into FormState. We need this information later in order to push data into the appropriate places. Here’s the code:

   1: public void FormEvents_Loading(object sender, LoadingEventArgs e)

   2: {

   3:     // we need a way to identify what task this InfoPath form represents in order to set the task to complete

   4:     // this is necessary because we will not be submitting this form the same way that a "normal" 

   5:     // task form gets submitted.

   6:     // So, we grab the Task Id via SPContext. We must do this during the loading event. After this event,

   7:     // the task id is no longer available. So we push it into the FormState.

   8:     FormState["TaskId"] = SPContext.Current.ItemId.ToString();

   9:     // Now using the Task item, we can also copy the originating listitem's id into FormState as well.

  10:     // This is needed for procssing during our submit routine.

  11:     FormState["ListItemId"] = SPContext.Current.Item["ItemId"].ToString();

  12: }

Ok. So now we need to handle the submission of the InfoPath form. Since we captured the necessary information to reach back to the list items in the FormState, everything is fairly straightforward.

   1: public void FormEvents_Submit(object sender, SubmitEventArgs e)

   2: {

   3:     // first action on submit is to push the provided data back into the ListItem that started the workflow

   4:     // To do this, we need the ListItemId that we pushed on load into FormState

   5:     XPathNavigator root = this.MainDataSource.CreateNavigator();

   6:     SPWeb web = SPContext.Current.Web;

   7:     SPListItem listItem = web.Lists["Proposals"].GetItemById(Int32.Parse(FormState["ListItemId"].ToString()));

   8:     web.AllowUnsafeUpdates = true;

   9:     listItem["Goal"] = root.SelectSingleNode("/my:myFields/my:Goal", this.NamespaceManager).Value;

  10:     listItem["Approach"] = root.SelectSingleNode("/my:myFields/my:Approach", this.NamespaceManager).Value;

  11:     listItem["Products"] = root.SelectSingleNode("/my:myFields/my:Products", this.NamespaceManager).Value;

  12:     listItem["PostDiscretionary"] = root.SelectSingleNode("/my:myFields/my:PostDiscretionary", this.NamespaceManager).Value;

  13:     listItem["Score"] = root.SelectSingleNode("/my:myFields/my:Score", this.NamespaceManager).Value;

  14:     listItem["Suggested Funding"] = root.SelectSingleNode("/my:myFields/my:RecommendedFunding", this.NamespaceManager).Value;

  15:     listItem.Update();

  16:     SPListItem task = web.Lists["Tasks"].GetItemById(Int32.Parse(FormState["TaskId"].ToString()));

  17:     // since the InfoPath form is not really submitting back to the task list, we have to complete the task in code

  18:     task["Status"] = "Completed";

  19:     task.Update();

  20:     web.AllowUnsafeUpdates = false;

  21:     // must have this next line or the submit will fail

  22:     e.CancelableArgs.Cancel = false;

  23: }

Couple of last things. We need to modify the feature.xml and workflow.xml in the workflow. In the feature.xml in the ElementManifests element, we added the element <ElementFile Location=”ProposalScoreSheet.xsn” />. Save it.

In workflow.xml, we do a little more. You need to open the form that you just designed in InfoPath in design mode. Then go to File –> Properties and copy the URN generated for the form. There may be an easier way to get this value, but I don’t know it. Then, in the xml in the MetaData element, add an element like: <Task1_FormURN>urn:schemas-microsoft-com:office:infopath:ProposalScoreSheet:-myXSD-2011-06-10T14-03-34</Task1_FormURN> substituting in the urn that you just copied for the one that I have here.

Then, in the Workflow element, under name, description, id, CodeBesideClass, CodeBesideAssembly you need to add the following line: TaskListContentTypeId=”0x01080100C9C9515DE4E24001905074F980F93160″> making sure that you don’t end up with an extra “>”. Save it.

Last thing, you need to create your install.bat to push everything to SharePoint properly. Here is a copy of my install.bat to see how I do my install:

   1: iisreset

   2: echo Copying the feature...

   3:  

   4: rd /s /q "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\wf_ITAP_Review_Assignment_OnCreate"

   5: mkdir "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\wf_ITAP_Review_Assignment_OnCreate"

   6:  

   7: copy /Y feature.xml  "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\wf_ITAP_Review_Assignment_OnCreate"

   8: copy /Y workflow.xml "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\wf_ITAP_Review_Assignment_OnCreate"

   9: copy /Y *.xsn "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\wf_ITAP_Review_Assignment_OnCreate"

  10: copy /Y ..\wf_ITAP_Review_Assignment_OnCreate\bin\debug\*.dll "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\wf_ITAP_Review_Assignment_OnCreate"

  11: echo Adding assemblies to the GAC...

  12:  

  13: c:\deploy\gacutil.exe -if bin\debug\wf_ITAP_Review_Assignment_OnCreate.dll

  14:  

  15: echo Verifying Infopath forms

  16: "%programfiles%\common files\microsoft shared\web server extensions\12\bin\stsadm" -o verifyformtemplate -filename ProposalScoreSheet.xsn

  17:  

  18: pushd %programfiles%\common files\microsoft shared\web server extensions\12\bin

  19: stsadm -o deactivatefeature -filename wf_ITAP_Review_Assignment_OnCreate\feature.xml -url http://localhost -force

  20: stsadm -o uninstallfeature -filename wf_ITAP_Review_Assignment_OnCreate\feature.xml -force

  21:  

  22: stsadm -o installfeature -filename wf_ITAP_Review_Assignment_OnCreate\feature.xml -force

  23: stsadm -o activatefeature -filename wf_ITAP_Review_Assignment_OnCreate\feature.xml -url http://localhost

  24:  

  25:  

  26: ::echo Doing an iisreset...

  27: popd

  28: :net stop sptimerv3

  29: :net start sptimerv3

  30: pause

 

After writing this all, I ran my code. I have an error somewhere and it is a weird one. Rather than delete this for now, I’ll just leave this warning and continue troubleshooting offline. When I find it, I’ll fix the blog. In the mean time, beware of what I have written! Ninja

Advertisements

About lelandholmquest

After serving in the Navy as a Reactor Operator on fast attack submarines, I earned both a Bachelor's and Masters in Information Technology from American InterContinental University and am currently working on my doctorate. I have a beautiful wife and two of the sweetest daughters a man could ask for. And I work for the greatest company: Microsoft. At Microsoft I work on the knowledge management system for Microsoft Services: Campus on Office 365.
This entry was posted in C# Programming, InfoPath 2007, Knowledge Management, SharePoint Coding, SharePoint Content Management Tips, Workflows. Bookmark the permalink.

2 Responses to Create an InfoPath form to collect specific information for a custom task

  1. I just like the helpful information you supply to your articles. I will bookmark your weblog and check once more here frequently. I’m relatively sure I will be told lots of new stuff right here! Best of luck for the next!

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