Possible Forms:
- Association form - this pops up when a WF is associated with a list.
- Initiation form - this pops up when a WF is initiated on a list item.
- Modification form - you'd use this WF to perform a modification on the WF.
- Task form - this can be used to substitute for the task created for the WF.
Important: The schema of the init and association form must be the same. If you want to have different Form, you should make both forms in one and hide the fields depending on the type of call.
This How To uses the example of a list selection when the workflow is initiated.
1. Create the Form
Open InfoPath and create a new blank form template. Select 'Enable browser-compatible features only'.
2. Get the Workflow Context
(http://msdn.microsoft.com/en-us/library/ms558892.aspx)
Create a XML File with the following content
<Context isStartWorkflow="true"isRunAtServer="false"provideAllFields="true"siteUrl=""/>
Following are the elements of the schema:
- Context Root element that represents the workflow context information being passed to the form. The Context element has the following attributes:
- isStartWorkflow Boolean; true if the form is being used as the workflow initiation form. You can use a specified form as both workflow association and initiation form, and it can present different views at each stage.
- isRunAtServer Boolean; true if the form is being opened on the server.
- provideAllFields Boolean; true if the form is being used as the last point of user interaction before the workflow starts. This means the form is being used either as a workflow initiation form or as a workflow association form for a workflow you have specified to start automatically.
- siteUrl String. The URL of the SharePoint site from which the form is being opened.
Note: The form does not use the actual values specified in the first three attributes; they are included solely to indicate that the attributes are defined as Boolean data types.
Save the file to your computer Add the context schema to your Form
- In Office InfoPath 2007, on the Design Tasks pane, select Data Source, and then click Manage Data Connection.
- In the Data Connections dialog box, click Add.
- In the Data Connection Wizard, select Create a new connection to, and then select Receive data. Click Next.
- Select XML Document, and then click Next.
- Browse to the location where you saved your Context.xml file, select it, click Open, and then click Next.
- Select Include the data as a resource file in the form template, and then click Next.
- Type Context as the data connection name, and ensure that Automatically retrieve data when form is opened is selected. Click Finish, and then click Close.
After you include the Context.xml file as a resource file in the form template, you no longer need the file. You do not need to include the file in your workflow solution.
3. Design the Form
Add a RepeatingTable Control (Lists – List – ListName, ListID)
Note: This control is just added for the creation of the Data Source Fields, it can be removed from the directly
Add a DropDown Control (SelectedList)
Set the Control Properties to look up the values in the Repeating Table Fields
using Microsoft.Office.InfoPath;
Add the Code
Click On Tools –> Programming –> Loading Event to open Microsoft Visual Studio Tools for Applications
Note: to install Microsoft Visual Studio Tools for Applications you have to go to Control Panel –> Add or Remove Programs –> Select your Office installation –> Change –> Add or Remove Features; You have to enable it for every Office Application with which you want to use it.
a) Include a Reference to Windows SharePoint Services to you project
b) use the following using statements
using Microsoft.Office.InfoPath;
using System;
using System.Xml;
using System.Xml.XPath;
using Microsoft.SharePoint;
using System.Collections.Generic;
c) Create Properties
Note: Member variables are not supported in browser-enabled forms. Instead, write and read these values from the FormState dictionary
private String SiteUrl {
get {
if (FormState["SiteUrl"] != null) {
return FormState["SiteUrl"].ToString();
} else {
return String.Empty;
}
}
set {
FormState["SiteUrl"] = value;
}
}
private String SelectedListID {
get {
if (FormState["SelectedListID"] != null) {
return FormState["SelectedListID"].ToString();
} else {
return String.Empty;
}
}
set {
FormState["SelectedListID"] = value;
}
}
d) add a method for removing the initial empty entry in the DropDown
private void emptyListDropDown() {
XPathNavigator myRoot = MainDataSource.CreateNavigator();
XPathNavigator xnContentTypes = myRoot.SelectSingleNode("/my:ListSelector/my:Lists", NamespaceManager);
List<XPathNavigator> nodesToDelete = new List<XPathNavigator>();
foreach (XPathNavigator option in xnContentTypes.Select("..//my:List", NamespaceManager)) {
nodesToDelete.Add(option);
}
//delete all nodes on the list
foreach (XPathNavigator option in nodesToDelete) {
option.DeleteSelf();
}
}
e) add a method for getting the Context Information
private void getContextData() {
XPathNavigator secDSNav = DataSources["Context"].CreateNavigator();
if (secDSNav.MoveToChild(XPathNodeType.All)) {
string myNamespace = NamespaceManager.LookupNamespace("");
SiteUrl = secDSNav.GetAttribute("siteUrl", myNamespace);
}
}
f) add methods for loading the Lists from SharePoint and add them to the DropDown Control
//fills the list dropdown with all non hidden lists from the site
private void loadSharePointLists(String siteUrl) {
using (SPWeb oWeb = new SPSite(siteUrl).OpenWeb()) {
foreach(SPList oList in oWeb.Lists){
if(!oList.Hidden){
createAndAddDropDownListItem(oList.Title, oList.ID.ToString());
}
}
}
}
private void createAndAddDropDownListItem(String name, String guid) {
string myNamespace = NamespaceManager.LookupNamespace("my");
XPathNavigator myRoot = MainDataSource.CreateNavigator();
XPathNavigator node = myRoot.SelectSingleNode("/my:ListSelector/my:Lists", NamespaceManager);
DeleteNil(node);
using (XmlWriter writer = node.AppendChild()) {
writer.WriteStartElement("List", myNamespace);
writer.WriteElementString("ListName", myNamespace, name);
writer.WriteElementString("ListID", myNamespace, guid);
writer.WriteEndElement();
writer.Close();
}
}
public void DeleteNil(XPathNavigator node) {
if (node.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance")) {
node.DeleteSelf();
}
}
g) adapt the Loading Method to load the DropDown Control
public void FormEvents_Loading(object sender, LoadingEventArgs e) {
emptyListDropDown();
getContextData();
String siteUrl = SiteUrl;
if (siteUrl != String.Empty) {
loadSharePointLists(siteUrl);
}
}
Add a Submit Button
IP forms are hosted in an aspx page or client application, so when the user wants to submit the form, he needs to have the submit button
a) create a connection to submit the xml data/string to the host environment (the host will handle the rest)
b) close the form so that it doesn’t just submit and stick around.
Add domain level trust
In InfoPath click on Tools->Form Options->Security and Trust
4. Create Code from your Form Schema
On the File menu, click Save As Source Files and save the form files in a folder on your local computer. There will be a file called myschema.xsd among the files you just saved.
Close InfoPath.
Open a Visual Studio 2005 Command Prompt which you can access via Start > Programs > Microsoft Visual Studio 2005 > Visual Studio Tools.
At the command-line prompt, use the cd command to navigate to the folder where you saved the form files. To generate a C# class for the form, at the command-line prompt type:
xsd myschema.xsd /c /l:cs
This will create a C# file named myschema.cs for the InfoPath form.
Note: Once you have created the class and examine it, you will notice that the name of the class is the same as the name of the root node of the InfoPath form. So if you want the generated class to have a meaningful name other than myFields, which is the default name assigned to the root node of an InfoPath form, you must change the name of the root node in InfoPath to the name you want the generated class to have, before you create the .NET class.
5. Adapt your Workflow to use the Form
Add myschema.cs to the project
Publish the Form
In InfoPath click File –> Publish –> Select ‘To a network location” –> Browse to the root folder of the Workflow Project –> empty the url –> publish
Copy the dll from the Form Source Folder into the root folder of the Workflow Project
Adapt Workflow.xml
In MetaData add <Association_FormURN>[URN FOR ASSOCIATION FORM]</Association_FormURN>
Set the AssociationURL attribute of the Workflow element to the following value:
AssociationUrl="_layouts/CstWrkflIP.aspx"
Note: To get the Form ID open your Form in InfoPath click on File –> Properties
Note:
AssociationUrl="_layouts/CstWrkflIP.aspx"
InstantiationUrl="_layouts/IniWrkflIp.aspx"
ModificationUrl="_layouts/WFMod.aspx"
Adapt Feature.xml
In the ElementManifest Tag add the xsn file and dll
<ElementFile Location="Foobar.dll"/>
<ElementFile Location="Foobar.xsn"/>
6. Use Form Data in the Workflow
To use the information from the InfoPath Form within the workflow use the following code
//deserialise InfoPath initiation form data
String initData = workflowProperties.InitiationData;
XmlSerializer xser = new XmlSerializer(typeof(ListSelector));
XmlTextReader reader = new XmlTextReader(new System.IO.StringReader(initData));
ListSelector listSelector = (ListSelector)xser.Deserialize(reader);
7. Attach the Workflow to you List or Library
Open the List –> Settings –> Workflow settings –> Add a Workflow –> Select the Workflow –> Enter a name –> Select the List and Start Options
After clicking OK you will see your form