Yes, I know this title sounds a bit odd, and the real title should be ‘When you are using an InfoPath task edit form, how do you use InfoPath data connection bindings to both retrieve and send data to a SharePoint 2007 workflow?’
So one day I was building an InfoPath 2007 task edit form and I wanted to send data to this form from inside of my workflow by using something like:
taskProperties.ExtendedProperties[“txtProductDescription”] = “Product ABC”;
I implemented an ItemMetadata.xml file with an ‘ows_txtProductDescription’ field, added a secondary data connection for it in my InfoPath form and followed all the normal steps and when I opened the form when my task was created, the data was there as expected.
However, what I didn’t realize was that when I closed the form and completed the task and then re-opened the form just to look at my previous settings, the data was gone! The form appeared as if it were a new form with default settings. To make matters worse, inside of the workflow I discovered that I could not use the task After properties to get the data out of the txtProductDescription field, it was always null. And this is where my multi-day odyssey of searching for the answer began.
To make things simple here, I’m just going to start with a simple form that has no binding and show you how to set things up. I hate to admit it took me several days and talking to several people to figure this out, so I hope it helps you shorten your path to a solution also.
- Microsoft Office SharePoint Server 2007 Enterprise Edition, SP1
- InfoPath 2007 – Browser enabled forms
- Visual Studio 2008 SP1 / C#
To begin with, here is my simple form entitled OrderRequestTask.xsn
I have three InfoPath controls here here, a Textbox named ‘txtProductDescription’, a Drop-Down List named ‘drpStatus’ and a button for submitting the data. This is a browser enabled form.
Create the ItemMetadata.xml file
Before we create our data connections we will need to create the ItemMetadata.xml file. This is what the file will look like:
Note the ‘ows_’ in front of the field names. This is a required prefix. Make sure you save this file as an XML file.
Setting Up the Data Connections
I will be using two data connections:
Update – this is a data connection that is used to submit the control(s) data into the workflow. Follow these steps to setup this data connection:
1. On the Design Task link (the Design Tasks toolbox should be on the right hand side of the form in InfoPath), select Data Source.
2. Select the Manage Data Connections… link.
3. In the Data Connections dialog box, select Add.
4. Select the Create a New Connection to and then Submit Data radio button.
5. Select Next.
6. Select ‘To the hosting environment, such as an ASP.Net page or a hosting application’ radio button. Basically at this point, InfoPath has no idea we are dealing with SharePoint, what we are saying is that we are going to submit the data back to whatever host opened the form, which will be the SharePoint task list.
7. Change the name of the data connection from Submit to Update and select Finish. This will complete your ‘main’ data connection. You can only have one main data connection and this is the only connection that can submit data to a form or other entity.
ItemMetadata – this data connection will read from an XML file named ItemMetadata.xml that will contain a reference to the controls on the form that can receive data from the workflow. It is very important here that you name this xml file EXACTLY ItemMetadata.xml, spelling is important, case is important, format is important….if any of these are incorrect, the data connection will not work. Another point, each form (whatever type of form it may be) that is receiving data from the workflow will have it’s own ItemMetadata.xml file, named ItemMetadata.xml so what I do is I have a separate directory for each form setup. Now technically, you could have a single ItemMetadata.xml file with several fields and only use the ones you need but that could get a bit confusing down the road.
8. The Data Connection dialog box should already be open, if not, select Manage Data Connections again to open it up.
9. In the Data Connections dialog box, select Add.
10. Select the Create a New Connection to and then Receive Data radio button.
11. Select Next.
12. Select ‘XML Document’.
13. Select Next.
14. Browse to where your ItemMetadata.xml file is and select it.
15. Select Next.
16. Make sure the ‘Include the data as a resource file in the form template or template part’ radio button is selected. What this means is that the ItemMetadata.xml file is actually going to become a part of the InfoPath form itself. Therefore, if you were to move this file after you get your form published, it would not matter. If you ever update your ItemMetadata.xml file you will also need to go through the steps above to refresh your data connection anyway.
17. Select Next then Finish. Now your Data Connections dialog box should look like this:
Binding the Controls to the Data Connections
As it stands right now, the way I did the drag and drop of the fields onto the form and setup my main data connection, made it so that both of these fields will submit their data into the workflow without any other modification from me. However, I want to be able to both receive data from the workflow AND submit the data to a workflow. This is where I spent so much time trying to figure out essentially, how to bind the controls to both data sources.
If you right click on the txtProductDescription field and select ‘Change Binding’ you will see the following dialog box:
You can see here that this field is data bound to the Main data source. You could of course choose the data source dropdown and then choose the ItemMetadata (secondary) data source but then the control will only receive data from the workflow and will not submit data to the workflow. Perplexing right?
To correct this situation, do the following:
1. Make sure the Text Box Binding dialog box above is closed.
2. With the txtProductDescription box still selected, move over to the Design Tasks toolbox and make sure the Data Connections window is open like below:
3. Right-click on txtProductDescription.
4. Select Properties:
5. In the Field or Group Properties dialog box, select the Fx (function) button:
6. In the Insert Formula dialog box, select the Insert Field or Group button:
7. From the Select Field or Group dialog box, select the Data Source drop-down and select ItemMetadata (Secondary) menu item.
8. Select the ows_txtProductDescription field and then select OK.
9. Select OK in the Insert Formula field and then OK and the Field or Group Properties dialog box.
10. Repeat steps 2 – 9, except choose the drpStatus drop-down field in the form. Note that if you don’t want or need to set this value from the workflow, you can just leave the binding as is.
11. Now you can save and publish your form. Since this is a task edit form and the workflow is going to determine where/how to pickup this file via it’s configuration files (feature.xml and workflow.xml), we will be publishing this form to a network location.
Publishing the Form
1. Select the File –> Publish menu item.
2. Select ‘To a network location’ then Next.
3. Browse to where you want to publish the file and select Next.
4. On the this page, make absolutely sure you clear out the text field in this window. If you do not, SharePoint will more than likely not let anyone open the form due to permissions.
5. Select Next. You will see a dialog box warning you of possible user access problems. Just select OK.
6. Select Publish.
7. Select Close.
At this point, I will defer to the experience of the student at to where they put the form so that the workflow can access it. More than likely you will have a sub-directory under your workflow projects feature directory to put the form in. You will then need to re-deploy your workflow project.
What about the code in the workflow itself?
Inside of the workflow in my CreateTask handler, I will have code that looks like this:
1: this.taskProperties.ExtendedProperties["ows_txtProductDescription"] = this.productDescription;
2: this.taskProperties.ExtendedProperties["ows_drpStatus"] = "Completed"
In my OnTaskChanged handler, I would have code that looks something like this:
1: string strProdDesc = this.taskAfterProperties.ExtendedProperties["txtProductDescription"].ToString();
2: bool statusComplete = this.taskAfterProperties.ExtendedProperties.ContainsValue("Completed");
A couple of things to note in the OnTaskChanged event is that I do not include the ‘ows_’ prefix in the field name and I am able to use ‘ContainsValue’ to get to the boolean status value.
In conclusion, I hope this helps someone out there prevent the time loss I had when attempting to figure this out. And as I’ve said before, if you know a better way of doing it, let me know!