Microsoft InfoPath 2010
The official blog of the Microsoft InfoPath team

  • Microsoft InfoPath 2010

    Submitting to a SharePoint List

    • 537 Comments

    As you know, submitting to a Microsoft Windows SharePoint form library from an InfoPath form is quite simple: just add a “submit” type of data connection to InfoPath and away you go. However, submitting to a SharePoint List is another matter. In this post, we will take a look at the steps necessary to enable this functionality.

    Step 1: Create the list

    1. Create a new custom list named: MyContacts
    2. From the Settings button choose List Settings
    3. Click Create Column
    4. Add the following columns/data types:

    • FirstName, Single line of text
    • LastName, Single line of text
    • Email, Single line of text
    • Phone, Single line of text

    The next step is to create a Collaborative Application Markup Language (CAML) template that contains the same XML nodes as the columns we added to our list – this will be used as a secondary data connection in the InfoPath Form Template.

    Step 2: Create the CAML template

    1. Launch Notepad (or any text editor)
    2. Copy and paste the following code to the Notepad document:

    <?xml version="1.0" encoding="UTF-8"?>
    <Batch OnError="Continue">
        <Method ID="1" Cmd="New">
            <Field Name='Title'></Field>
            <Field Name="FirstName"></Field>
            <Field Name="LastName"></Field>
            <Field Name="Email"></Field>
            <Field Name="Phone"></Field>
        </Method>
    </Batch>

    3. Save this as: Add List Item Template.xml

     

    Step 3: Create the InfoPath Form Template

    1. Create a new, blank, browser-compatible form template
    2. Add a “Receive” type secondary data connection to the Add List Item Template.xml file created in Step #2. (Make sure the options “Include the data as a resource file in the form template” and “Automatically retrieve data when the form is opened” are enabled.)
    3. Add a “Receive” type secondary data connection to the “MyContacts” SharePoint List created in Step #1 and make sure the option “Automatically retrieve data when the form is opened” is enabled.
    NOTE: Be sure to include the “Title” field along with the custom fields we created.

    Each SharePoint list is created with a unique identifier called a GUID. In order to submit items to a SharePoint list, you must know the unique GUID for that list. These next steps will enable you to identify the GUID for your “MyContacts” list.

    Step 4: Identify the list GUID

    1. Open a browser and navigate to the MyContacts list
    2. From the Settings menu choose List Settings
    3. In the browser’s address bar you will see the URL appended with “List=”

     

    4. Copy everything after the equals sign and paste this into a text editor as we will need this value later on.

    NOTE: We will need the list GUID to be formatted as “{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}”. If your GUID appears as above with the hyphens and braces “escaped” (i.e. %7B for the braces and %2D for the hyphens) then you will need to replace the escaped characters with the braces and hyphens so when we use this GUID later, it will appear as: {1E76517B-2C36-4473-A420-A737D98589BC}

    Step 5: Add controls to the InfoPath Form Template

    1. Open the Data Source Task Pane
    2. From the Data Source dropdown box choose the “MyContacts” connection

    3. Right-click on “MyContacts” and choose Repeating Table – this will add a repeating table bound to that connection to your View
    4. From the Data Source dropdown box choose Main
    5. Add a text box to the “myFields” node named: ListName and set the Default Value property to the GUID value of your list – we will use this node to specify the list when we perform the Submit operation

     

    To update the SharePoint list we will be using the “UpdateListItems” method of the SharePoint “lists.asmx” web service. This web method requires a couple of parameters (the list name and what gets updated) – now that we have added the “ListName” node which contains the GUID and we have the Add List Item Template XML data connection which describes our data structure we have all the necessary information to add the “UpdateListItems” web method!

    Step 6: Add the “lists.asmx” web service

    1. Add a new “Submit” type of web service data connection to the “lists.asmx” web service – this is typically located at: http://servername/_vti_bin/lists.asmx
    2. Select the “UpdateListItems” operation
    3. Double-click the “listname” parameter and assign the “my:ListName” node as the value

    4. Double-click the “updates” parameter, select the “Add list Item Parameter” data source, select “Batch” and click OK
    5. For the “Include” option select “XML subtree, including selected element”

    6. Complete the Data Connection Wizard

    Now that we have all the connections that are required, we now need to add the “submit” functionality to the form template.

    Step 7: Add Submit functionality

    1. Display the Data Source Task Pane
    2. From the Data Source dropdown box choose the Add List Item Template data connection
    3. Drill down through the data source, right-click on the Field node and choose Repeating Table

     

    We need to change the text box control in the “Name” column to Read-only – if these values were to be changed it would affect the CAML and the submit would fail.
    • Double-click on the text box in the Name column of the Repeating Table
    • Select the Display tab
    • Enable the Read-only property and click OK
    • Add a new Button control to the View
    • Double-click the button to display the Properties
    • Click the Submit Options button
    • Enable the option “Allow users to submit this form”
    • Enable the option “Perform custom action using Rules” and click the Rules button
    • Click the Add button
    • Click the Add Action button
    • From the Action dropdown box choose “Submit using a data connection”, select the “Web Service Submit” data connection and click OK
    • Click the Add Action button
    • From the Action dropdown box choose “Query using a data connection”, select the “MyContacts” data connection and click OK (this will automatically refresh the list in InfoPath so you can see the newly added record)

    • Click OK until you are back to your form

    NOTE: If you want to automatically clear out the submitted values, add another action to this Rule to “Set a field’s value” and the only option you need to specify is the “Field” option – select the “Field” node from the “Add List Item Template” data connection and then simply leave the Value option blank.

    Step 8: Test!

    1. Click the Preview button to preview the form
    2. Fill in values for each of the fields: Title, First Name, Last Name, E-mail and Phone

    3. Click the Submit button – the contact information should be submitted successfully and the “MyContacts” list automatically updated!

    A special thanks to Matt Faus of InfoPathDev for for initially posting this solution!

    Scott Heim
    Support Engineer

  • Microsoft InfoPath 2010

    Using the Contact Selector Control

    • 398 Comments

    (This post applies to InfoPath 2007. If you're using InfoPath 2010, then you should check out this post instead.)

    We have seen a number of requests on how to allow a user to enter (or select) a person’s name or logon alias and then validate that user against their Active Directory without using code. This has been especially true in workflow scenarios where User A needs to enter in the name of User B – the next person in the workflow process.

    Well, InfoPath 2007 ships with a control called Contact Selector Control that will resolve these issues! You may have seen our older article on the subject; this one aims to dive in deeper.

    The Contact Selector control is an ActiveX control but it is a special cased control, in that it can also be used in InfoPath browser forms. To use this control there are specific steps that need to be taken – let’s take a look at those now.



    Step 1: Add the Contact Selector control to your Controls Task Pane

    1) From the Controls Task Pane click the Add or Remove Custom Controls link

    2) Click the Add button

    3) On the first screen of the Add Custom Control Wizard select ActiveX control and click Next

    4) From the list of controls, choose Contact Selector and click Next

    5) Select “Don’t include a .cab file” and click Next

    6) For Binding Property select Value and click Next

    7) From the Field or group type box choose Field or group (any data type) and click Finish

    8) Click Close and then click OK

     

    Step 2: Create the data structure for the Contact Selector Control

    The Contact Selector control needs to have a specific data structure to work properly – this is documented on the “Items” tab of the Properties screen for the control; however, we’ll include that information here as well.

    **IMPORTANT!** Spelling and capitalization must be exactly the same, starting with the “Person” group!

    1) Add a non-Repeating Group named: gpContactSelector

    2) Add a Repeating Group named: Person

    3) Add the following 3 text fields to the Person group: DisplayName, AccountId and AccountType



    Step 3: Add and bind the Contact Selector control to the View

    1) Drag the gpContactSelector Group to the View and select “Contact Selector” from the list of controls

    2) You’re almost done…! :-)



    Step 4: Add a secondary data source XML file which specifies the SharePoint server

    The Contact Selector control needs to know the “context” of where the user validation should occur. These steps are not necessary if you are only displaying the form in a browser from SharePoint – in this case, it uses the context of the site from where it was provisioned; however, if you are in a mixed client/browser scenario you will need to include this XML file so forms opened in the client can use this functionality.

    1) Launch Notepad

    2) Copy and paste this one-line XML:

    <Context siteUrl="http://<servername>"/>

    **NOTE: Replace <servername> with the name of your server

    3) Save this as: Context.xml (again – naming and capitalization are important)

    4) Add Context.xml as a “Receive” type Secondary Data Connection to your form template and make sure the option “Include the data as a resource file” is enabled



    Step 5: Test!

    You should now be able to Preview the form, enter a name or logon alias, click the “Check Names” button and resolve the name! Alternatively you could click the “To” button to perform a Search if you do not know the complete name of the user.

    One other important point: if this control is something you will use numerous times, this process works great to create a “Contact Selector Template Part” – then you only have to complete these steps one time!

    Scott Heim
    Support Engineer

  • Microsoft InfoPath 2010

    Submitting to 'this' document library

    • 166 Comments

    Have you ever needed to develop an InfoPath form template that submits back to a SharePoint document library but you did not initially know the server or library name when developing the form? Or have a scenario where your InfoPath form template could be published (or added as a content type) to multiple SharePoint document libraries and you need the submit location to be dynamic? Well read on to find out how you can do this!

    When you create an InfoPath form template that needs to be able to submit to a SharePoint document library, you need to specify that connection in the initial design of the form template. However, at run time you can use managed code to determine the server and library name where the form was launched and then modify the “FolderUrl” property of the submit data connection so the form is submitted to the appropriate library.

    So let’s get started setting up this sample. The C# walkthrough below uses the new InfoPath 2007 managed object model; below, you will find attached the same logic implemented in InfoPath 2003 managed object model and in InfoPath 2003 JScript.

    Step 1: Create a sample InfoPath Form Template

    Create a browser-compatible form template as following:

    1. Add 3 text box controls, all with a data type of text, named as follows: strFormURL, strLocation and strFolderName
    2. Add a “Submit” data connection named “Main submit”:
      • Set the document library name to a dummy SharePoint document library (i.e. http://server/dummyLib)
      • Use the concat function to concatenate the strFolderName field and _Test for the File Name property: concat(my:strFolderName, "_Test")
      • Enable the Allow overwrite if file exists property
    3. Set the Security Level of the form to Full Trust and sign the form template with a digital certificate
    4. Enable the Submit functionality (Tools | Submit Options) and choose the “Perform custom action using code” option

    Now that we have the form, controls and submit functionality, let’s add the code to make this process work:

     

    Step 2: Add the code

    • Click the Edit Code button on the Submit Options dialog
    • Create the following FormState Dictionary object – this will be used to store the form’s location when the form is initially opened:

    private object _strUri
    {
       get { return FormState["_strUri"];
      
    set { FormState["_strUri"] = value; }
    }

     

    • Add the following code to the Forms Loading event: 

    // Get the Uri (or SaveLocation in a browser form) of where
    // the form was opened.
    // See if the form was opened in the browser

    Boolean OpenedInBrowser = Application.Environment.IsBrowser; 

    // If so, we will get the "SaveLocation" from the InputParameters

    if (OpenedInBrowser)
      
    _strUri = e.InputParameters["SaveLocation"].ToString();
    else  

       //If it was opened in the client, we will get the Uri
      
    _strUri = this.Template.Uri.ToString();

     

    // Populate the fields on the form - keep in mind, this

    // not necessary - this is simply to see the results

    PopulateLibInfo(OpenedInBrowser);

     

    • Add the following procedure to the Forms class: 

    private void PopulateLibInfo(Boolean OpenedInBrowser)

    {

    // Create a Navigator object for the main DOM
    XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();

     

    // Create Navigator objects for each field

    XPathNavigator xnFormURL = xnDoc.SelectSingleNode("my:myFields/my:strFormURL", this.NamespaceManager);
    XPathNavigator xnLocation = xnDoc.SelectSingleNode("my:myFields/my:strLocation", this.NamespaceManager);

    XPathNavigator xnFolderName = xnDoc.SelectSingleNode("my:myFields/my:strFolderName", this.NamespaceManager);

     

    // Get the Uri stored in the FormState Dictionary variable

    string strUri = _strUri.ToString();

     

    // Create a variable to store the path (URL) to the document library

    string strPath = "";

    if (OpenedInBrowser == true) {

       //If we are open in the browser, the strUri value is just

       //the server name and library - so we just need to get

       //the URL without the last "/"

       strPath = strUri.Substring(0, strUri.LastIndexOf("/"));

    } else {

       // Parse just the path to the document library -

       // this would return something like this:

       //  http://server/library

       strPath = strUri.Substring(0, strUri.IndexOf("Forms") - 1);
    }


    // Now, parse the URL to where the document library resides;
    // this would return something like:

    //    http://server or http://server/site
    string strLoc = strPath.Substring(0, strPath.LastIndexOf("/"));


    // Lastly, parse the URL to return just the document library name -

    // in this case,we are looking for the last "/" character

    // knowing that what comes after this is the document library name

    string strFolder = strPath.Substring(strPath.LastIndexOf("/") + 1);

     

    // Populate the fields on the form – we will use these

    // values in the Submit process

    xnFormURL.SetValue(strUri);

    xnLocation.SetValue(strLoc);

    xnFolderName.SetValue(strFolder);
    }

     

    • Add the following code to the form’s Submit event:

    // Create a Navigator object for the main DOM
    XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();


    // Create Navigator objects for the fields we will

    // use to modify the FolderUrl
    XPathNavigator xnLocation = xnDoc.SelectSingleNode("my:myFields/my:strLocation", this.NamespaceManager);
    XPathNavigator xnFolderName = xnDoc.SelectSingleNode("my:myFields/my:strFolderName", this.NamespaceManager);

     

    // Get a reference to the submit data connection

    FileSubmitConnection fc = (FileSubmitConnection)this.DataConnections["Main submit"]; 

     

    // Modify the URL we want to submit to by concatenating the

    // xnLocation and xnFolderName values

    fc.FolderUrl = xnLocation.Value + "/" + xnFolderName.Value;

     

    // Execute the submit connection

    try

    {

       fc.Execute();

       e.CancelableArgs.Cancel = false;

    }

    catch (Exception ex)

    {

       e.CancelableArgs.Cancel = true;
    }

     

    • Build and save the project
    • Publish and test

    And that is it! You now have an InfoPath form template that will submit to whatever document library the form was opened from so you do not need to know this information when designing the template.

     

    Scott Heim

    Support Engineer

  • Microsoft InfoPath 2010

    Populating form data from SharePoint List Views

    • 105 Comments

    The SharePoint list data connection in InfoPath is a great declarative way to bring in data from a SharePoint list, but it does have some limitations.  For those willing to put in a little extra effort, there’s much more that can be done with SharePoint lists: you can bind to views based on these lists. Here are the steps for creating the connection to a list view.

    First, let’s get the URL:

    1. Navigate to the SharePoint site that contains the list, for example:
    http://contoso/sites/sales/Sales%20Contacts/Forms/AllItems.aspx
    2. Go to “Modify settings and columns”
    3. Copy the List={GUID} portion of the URL and paste this into a buffer like a Notepad window.
    4. In Notepad, create the following URL (the blue portion us taken from the step 1 URL, and the red portion must be added.

    http://contoso/sites/sales/_vti_bin/owssvr.dll?Cmd=Display&List={GUID}&XMLDATA=TRUE&noredirect=true

    This will return an xml file that can be used in an XML file data connection, as if it came from a file system.  After this, you can use the URL as the location of an XML data file when creating a data connection.

     

    Two caveats:
    - Form users must have read access to the SharePoint list.
    - During creation of the data connection, do not include the file in the form template, as it should be dynamically generated from the SharePoint list.

     

    Some tricks:
    1. When you’re in “Modify settings and columns,” if you click on one of the views in the list at the bottom, you should note that the URL is “enriched” with &View={ANOTHER_GUID}.  If you would prefer to use the columns from that view, you should similarly enhance the URL you use above.
    2. You can also use the url to filter data rows based on column values. For example:

    http://contoso/sites/sales/_vti_bin/owssvr.dll?Cmd=Display&List={115BC7B7-0A82-403E-9327-F3C73E6D37F3}&XMLDATA=TRUE&noredirect=true&FilterField1=xd__x007b_52AE1EF8_x002d_28E7_x002d_4CE4_x002d_AE23_x002d_54E23E80DDB5_x007d_&FilterValue1=Approved

    Note: be sure to remove the “ows_” from the beginning of the FilterField ID.

     

    With this filter, the XML file returned will be filtered to only display those projects that have been approved.  Without the green portion, you would see all the projects.

     

    In order to populate other fields with data from WSS, you create the secondary data source just like above, then in form code or script, you can use GetDOM(“dataSource”) and walk the DOM normally, updating the main DOM as appropriate.

     

    Ed Essey
    Program Manager

  • Microsoft InfoPath 2010

    What's New in InfoPath 2010?

    • 63 Comments

    Here's a quick overview of some of the great new features in InfoPath 2010. Stay tuned for upcoming posts with more details!

    Microsoft InfoPath 2010 makes it easier than ever to design electronic forms. InfoPath now includes the Office Fluent UI and allows the creation of powerful, interactive forms, without having to write any code. With a few clicks, Office users can customize SharePoint list forms, add custom layouts and rules to validate the data, and take them offline in SharePoint Workspace.

    IT professionals can create custom forms for document workflows and Office Business Applications that include managed code, digital signatures and that connect to line of business data.

    In InfoPath 2010, we’ve made some big investments to make it much easier to build rich forms-based applications on top of the SharePoint Server 2010 platform.

    Quickly Design Forms with Easy-to-Use Tools
    New features to help you quickly and easily create forms include our new Fluent UI, pre-built layout sections, out-of-the-box rules, improved rules management, and varied styles. 

    The New tab in the Designer Backstage presents you with the available form templates that you can choose from. Most templates start you off with a default layout table.

    InfoPath 2010 Designer New Tab

    Stay tuned for more details on our new and improved form design features!

    Layout your Forms Using Pre-built Page and Section Layouts
    Laying out your form and making it look more attractive is now easier than ever. Insert one of our pre-built page layouts to give your form structure. Then, insert some section layouts into the page layout to start building your form.

    Page and Section Layouts in InfoPath Designer:

    InfoPath 2010 Designer Layouts


    New and Improved Controls
    We’ve added some new controls and narrowed the feature gap between client and browser forms, ensuring a more consistent form filling experience for all our users.

    New controls in InfoPath 2010 include:

    • Picture buttons – Instead of the default gray button, use any image as a button in your form.
    • Hyperlink capabilities –Allow users to insert their own hyperlinks when filling out forms.
    • Date and time picker – Allow users to insert dates and times in their forms
    • Person/Group pickers – Updated! This is now a first class control and is included by default in the Controls gallery.
    • Signature Line (Editor Only) – Allow users to digitally sign a  form

    Controls and functionality that are now supported in browser forms include:  

    • Bulleted, numbered, and plain lists, multiple selection list boxes, Combo boxes, Choice group and sections, and Filtering functionality.

    Add Rules to your Forms
    With our new out-of-the-box rules (or quick rules) and improved rules management UI, you can easily add rules to validate data, format your form, or perform other actions with just a couple of clicks, and without any code.

    Quick Rules in InfoPath Designer:

    InfoPath 2010 Designer Quick Rules

    Publish Forms Quickly
    Our new “quick” publish functionality allows you to publish forms in a single click (no more clicking through the Publishing Wizard every time you want to make an update to your forms!)
     

    Create Forms for SharePoint Lists
    Using InfoPath, you can now extend and enhance the forms used for creating, editing and viewing items in a SharePoint list. In a browser, simply navigate to a SharePoint list, and on the SharePoint Ribbon under List Tools, choose the Customize Form option. This will automatically generate a form which looks very similar to the default out-of-the-box SharePoint list form.

    You can then customize and enhance this form by modifying the layout, creating additional views or pages, and adding rules to validate your data, show or hide sections of the form or set a fields value (to name just a few of the options).

    Example of Customized SharePoint List Form:

     Customized SharePoint List Form
    Stay tuned for more details on SharePoint List Customization!

    We recommend using a form associated with a SharePoint list when possible. This provides the most straightforward design and form management experience. However, there are more complex scenarios where using a form associated with a form library is preferred e.g. if your form has a complex schema or if you need to add code to your form. 

    Create SharePoint Applications
    With InfoPath 2010, SharePoint Server 2010, and SharePoint Designer 2010, you can easily create powerful team, departmental or enterprise applications on top of SharePoint Server.

    • Form-based applications: InfoPath forms can be integrated with components such as workflow, reporting, and custom Web pages to create rich form-based applications.  
    • Document Workflows: InfoPath can be used to design custom workflow initiation and task forms that drive document management processes.
    • Business Connectivity Services: Integrating with BCS, it is straightforward to design InfoPath forms that create, read, update, and delete business data from a back-end system. 

    Stay tuned for more details on creating SharePoint applications!

    Create Mashups using the InfoPath Form Web Part
    Now, without writing a single line of code, you can host your InfoPath browser forms in Web pages by simply adding the InfoPath Form Web Part to a Web Part page. You can also connect it to other Web Parts on the page to send or receive data.

    Stay tuned for more details on the InfoPath Form Web Part!

    Build Forms with Code
    Using Visual Studio Tools for Applications, you can add managed code to your forms.

    Stay tuned for more details on programming with InfoPath! 

    InfoPath Editor
    The InfoPath 2010 Editor Fluent user interface provides a much improved, simpler user experience for filling out forms.

    Form opened in InfoPath 2010 Editor:

    InfoPath 2010 Filler
     
    SharePoint Workspace
    InfoPath 2010 is the forms technology used by SharePoint Workspace 2010 for creating and filling out forms.

    InfoPath Forms Services Administration and Management
    We have invested in many improvements to make it easier to manage your InfoPath Forms Services as a component of Microsoft SharePoint Server 2010.

     

    We hope you enjoy using InfoPath 2010 and look forward to getting your feedback!

    The InfoPath Team

     

  • Microsoft InfoPath 2010

    Email Submit "To" line (loops in formulas)

    • 62 Comments
    Everyone likes InfoPath's email data connection because it lets you collect forms using email only, no other infrastructure required (no need for Windows SharePoint Services, SQL Server, or even a file share). We've built even more Outlook integration in InfoPath 2007 Beta, but since most of you don't have that yet, let me share a tip that will work in both InfoPath 2003 and 2007.
     
    The basics: Single dynamic email address
    As your probably know, the To and CC line of the email data connection can come from a textbox in the form by using a formula. To do that, just use the Fx button next to the To line in the data connection wizard:
     
     
    The trick: Multiple email addresses from repeating controls
    Some forms have a list of names they want to send to, but the simple formula above won't work for that.
     
    For example, consider a repeating table that looks like this:
     
     
    With this data source (note that "person" is repeating):
     
     
    So you want to produce this semicolon-separated list of e-mails:
     
     
     
    A good instinct is to use the "concat" function, but unfortunately that only works on the first element in a repeating structure.
     
    So then comes the team insight: Our "eval" function returns a list of nodes which actually share an anonymous parent. That means you can use one eval functions to create a list of the email addresses, then wrap it in another eval function that gets the parent of that list.
     
    Voila, here's the formula to solve the problem:
    eval(eval(person, "concat(my:email, ';')"), "..")
     
    (Note that "person" can be inserted from the data source, but "my:email" needs to be typed by hand or you'll get an error.)
     
    For the curious: Here's how it's done
    Let's break down that XPath formula from the inside out:
     
    • "concat(my:email, ';')" - Adds a semicolon to each email address.
    • eval(person, "concat(my:email, ';')") - Loops through each person to create a list of email addresses
    • eval(eval(person, "concat(my:email, ';')"), "..") - Gets the anonymous parent of the email addresses, and converts them to a string.
     
    So the end result returns the contents of that anonymous parent, which is a series of semicolon-delimited email addresses. Phew!
     
    In summary
    We are using two tricks here:
    • The fields returned by eval() all have the same anonymous parent (feature of InfoPath's function)
    • The string value of a parent is the concatenation of all its children (W3C spec’ed)
     
    - David Airapetyan (Software Design Engineer) and Ned
  • Microsoft InfoPath 2010

    Calculating Elapsed Time…without code!

    • 59 Comments

    UPDATE: Due to the number of requests for adding more columns to this sample, I have re-designed the sample. If I have time in the future I will update the steps to create this new design; however, for now you can download the updated design here to see the changes. The expressions are very similar to the original design but I now use a repeating table for entering "break" times so you can have as many as you need! 

    How many times have you needed to calculate the difference between time entries…only to find out the only way to accomplish this was to write custom code? Well no more! If your time entries will not cross days, then you can use a number of functions and expressions to parse the entered times and calculate the difference. In the sample below we will show you the types of expressions that are needed for these calculations to work – I would encourage you to first create this sample as documented as the expressions are not for the “faint of heart!” :-)

    Note: if you choose to copy/paste the expressions for this sample, you will use the Default Value box for each field and after clicking the “fx” button, be sure to also enable the “Exit XPath” option before you paste these expressions.

    If you'd like to take a look at the completed version of this sample, here is the .xsn file - make sure to save it locally before opening it.

    Create the data structure

    1) Add a Repeating Table to your View with 4 columns

    2) Rename the fields and specify the data types as follows, from left to right:

    Name Data Type
    myDate Date (date), Format: *3/14/2001
    StartTime Time (time), Format: *9:46 AM
    EndTime Time (time), Format: *9:46 AM
    ActualTime Text (string)

    3) Change the first field in the table to a Date Picker control

     
    4)  Add 2 additional fields to the Repeating Group node (these will not be shown on the view – they are used to aid in the calculations)

    Name Data Type
    ElapsedTime Text (string)
    TotalMinutes Decimal (double)


    5) Add one final field to calculate the sum of all the entries – this should be added to the myFields node…not the Repeating node

    Name Data Type
    TotalTime Text (string)

    Your final data structure should look like this:

    And your form could look like this:

     

    Adding the expressions…let the fun begin!

    The first step is to convert the StartTime and EndTime values to minutes – this makes the calculation a bit easier. In addition, we don’t want to execute this calculation if either the StartTime or EndTime is blank. So to perform this “conditional statement”, we’ll use the logic explained in this blog entry.

    Step 1: Parse the Hours and Minutes

    1) We first need to parse the “hours” and convert this to minutes by multiplying that value by 60. To do this we will use the “substring-before” function to look for the colon (“:”) in the time field and extract the value before the colon:

    substring-before(../my:EndTime, ":") * 60)
    substring-before(../my:StartTime, ":") * 60

    2) To each of these values, we need to add the minutes that were entered after the colon. Now when time values are stored in the underlying XML, they are stored in this manner: hh:mm:ss. So to pull just the minutes entered, we will use a combination of the “substring-before” and “substring-after” functions since we need the value entered “after” the first colon and “before” the last colon:

    substring-before(substring-after(../my:EndTime, ":"), ":")
    substring-before(substring-after(../my:StartTime, ":"), ":")

    3) Now, at this point we could place each of these expressions together to get the total hours and minutes for each time entry:

    ((substring-before(../my:EndTime, ":") * 60) + substring-before(substring-after(../my:EndTime, ":"), ":"))
    ((substring-before(../my:StartTime, ":") * 60) + substring-before(substring-after(../my:StartTime, ":"), ":"))

    4) Keep in mind, we don’t want this expression to execute if either the StartTime or EndTime fields are empty and we also need to subtract the StartTime total minutes from the EndTime total minutes. So to do this we will use the “substring” function in conjunction with a “condition.” The substring function has the following signature:

    substring([String Value], [Starting Position], [Condition/Length])

    To incorporate our expressions into the substring function, it would look like this:

    Substring([EndTime – StartTime], 1, EndTime != “” and StartTime != “”)

    EndTime expression:

    ((substring-before(../my:EndTime, ":") * 60) + substring-before(substring-after(../my:EndTime, ":"), ":"))

    StartTime expression:

    ((substring-before(../my:StartTime, ":") * 60) + substring-before(substring-after(../my:StartTime, ":"), ":"))

    Starting position: 1

    Condition expression (that if true, evaluates to the length of what we want to return so we use the “string-length” function to get the length of our initial expression):

    (../my:StartTime != "" and ../my:EndTime != "") * string-length(((substring-before(../my:EndTime, ":") * 60) + substring-before(substring-after(../my:EndTime, ":"), ":")) - ((substring-before(../my:StartTime, ":") * 60) + substring-before(substring-after(../my:StartTime, ":"), ":")))

    So our final expression for the TotalMinutes field would look like this:

    substring(((substring-before(../my:EndTime, ":") * 60) + substring-before(substring-after(../my:EndTime, ":"), ":")) - ((substring-before(../my:StartTime, ":") * 60) + substring-before(substring-after(../my:StartTime, ":"), ":")), 1, (../my:StartTime != "" and ../my:EndTime != "") * string-length(((substring-before(../my:EndTime, ":") * 60) + substring-before(substring-after(../my:EndTime, ":"), ":")) - ((substring-before(../my:StartTime, ":") * 60) + substring-before(substring-after(../my:StartTime, ":"), ":"))))

     

     

    Step 2: Convert resulting Total Minutes to hours and minutes

    This expression will use the same basic logic we used above: first divide the resulting total minutes field by 60 to see how many hours have elapsed. If the result of that division contains a decimal point (i.e. 90 minutes / 60 = 1.5) then parse the value before the decimal point (for the hours) and then use the “mod” function to return the balance of the minutes.

    1) We need to divide the TotalMinutes field by 60 to get how many hours have elapsed; however, we also need to check if the resulting value contains the decimal point. So the first expression will use the “substring” function so we can incorporate the conditional test. For the conditional test, we will use the “contains” function to see if the result contains the decimal point:

    contains(../my:TotalMinutes div 60, ".")

    So our initial expression would be as follows: this incorporates the “concat” function so if the resulting value contains a decimal point, we will parse that value, concatenate a colon and the concatenate the result of TotalMinutes mod 60:

    substring(concat(substring-before(../my:TotalMinutes div 60, "."), ":", ../my:TotalMinutes mod 60), 1, contains(../my:TotalMinutes div 60, ".") * string-length(concat(substring-before(../my:TotalMinutes div 60, "."), ":", ../my:TotalMinutes mod 60)))

    2) If the resulting expression does not contain a decimal point, then we will simply concatenate a colon with the results of TotalMinutes mod 60:

    substring(concat(../my:TotalMinutes div 60, ":", ../my:TotalMinutes mod 60), 1, not(contains(../my:TotalMinutes div 60, ".")) * string-length(concat(../my:TotalMinutes div 60, ":", ../my:TotalMinutes mod 60)))

    3) So our final expression for the ElapsedTime field would be as follows:

    concat(substring(concat(substring-before(../my:TotalMinutes div 60, "."), ":", ../my:TotalMinutes mod 60), 1, contains(../my:TotalMinutes div 60, ".") * string-length(concat(substring-before(../my:TotalMinutes div 60, "."), ":", ../my:TotalMinutes mod 60))), substring(concat(../my:TotalMinutes div 60, ":", ../my:TotalMinutes mod 60), 1, not(contains(../my:TotalMinutes div 60, ".")) * string-length(concat(../my:TotalMinutes div 60, ":", ../my:TotalMinutes mod 60))))

     

     

    Step 3: Final Formatting - the ActualTime field

    The way the expression is written for the ElapsedTime field, if the resulting minutes is less than 10, only a single value will be returned (i.e. 0:9). Because of this, we want to test for this condition and if the minutes are less than 10, then concatenate a zero (“0”) before that value so the time appears correct. Now this expression could possibly have been incorporated into the ElapsedTime expression but for ease and clarity, I separated these two steps into different fields.

    This expression uses the “string-length” function to determine the length of the string after the colon. If the length is 2 (minutes are greater than 9) then simply concatenate the hours, a colon and the minutes. However, if the length is 1 (minutes are less than 10) then concatenate the hours, a colon with a zero (“:0”) and the minutes. Like before, we will use the “substring” function with a condition statement to determine what to return:

    concat(substring(concat(substring-before(../my:ElapsedTime, ":"), ":", substring-after(../my:ElapsedTime, ":")), 1, (string-length(substring-after(../my:ElapsedTime, ":")) = 2) * string-length(concat(substring-before(../my:ElapsedTime, ":"), ":", substring-after(../my:ElapsedTime, ":")))), substring(concat(substring-before(../my:ElapsedTime, ":"), ":0", substring-after(../my:ElapsedTime, ":")), 1, (string-length(substring-after(../my:ElapsedTime, ":")) = 1) * string-length(concat(substring-before(../my:ElapsedTime, ":"), ":0", substring-after(../my:ElapsedTime, ":")))))

    Step 4: Create the TotalTime expression for keeping a running total of the elapsed time

    The last step is to create the TotalTime expression – this is similar to the ActualTime expression except we now incorporate the “sum” function to get the running total:

    concat(substring(concat((sum(../my:group1/my:group2/my:TotalMinutes) - sum(../my:group1/my:group2/my:TotalMinutes) mod 60) div 60, ":", sum(../my:group1/my:group2/my:TotalMinutes) mod 60), 1, (sum(../my:group1/my:group2/my:TotalMinutes) mod 60 > 9) * string-length(concat((sum(../my:group1/my:group2/my:TotalMinutes) - sum(../my:group1/my:group2/my:TotalMinutes) mod 60) div 60, ":", sum(../my:group1/my:group2/my:TotalMinutes) mod 60))), substring(concat((sum(../my:group1/my:group2/my:TotalMinutes) - sum(../my:group1/my:group2/my:TotalMinutes) mod 60) div 60, ":0", sum(../my:group1/my:group2/my:TotalMinutes) mod 60), 1, (sum(../my:group1/my:group2/my:TotalMinutes) mod 60 < 10) * string-length(concat((sum(../my:group1/my:group2/my:TotalMinutes) - sum(../my:group1/my:group2/my:TotalMinutes) mod 60) div 60, ":0", sum(../my:group1/my:group2/my:TotalMinutes) mod 60))))

    Step 5: Test!
    Enter a Start and End Time in the form of: h:mm AM(PM), such as: 8:00 AM and 5:00 PM – the ActualTime field should display the difference (as 9:00) and if you continue adding rows, the TotalTime field should reflect the running total.

    This functionality allows you to create elapsed time scenarios that work in both client and browser forms without writing one line of code!

    Scott Heim
    Support Engineer

  • Microsoft InfoPath 2010

    Person / Group Picker Improvements in InfoPath 2010

    • 51 Comments

    Hi, this is Frank Mueller, a developer on the InfoPath team. In this post which is the first of two blog posts about the Person / Group picker, I want to tell you about the improvements we’ve made to this control in InfoPath 2010.

    The Person / Group Picker (aka contact selector) control allows you to type or select users and groups from a SharePoint site, and validate those users against a directory provider. In InfoPath 2010, the Person / Group Picker control is now a 1st class citizen and is available out of the box in the controls gallery! With the new and improved person / group picker, we have eliminated the detailed steps required to insert and configure this control in your forms (the blog post outlining these steps has been one of our most viewed posts). In addition to making the control available in the controls gallery out of the box, we have added new features to improve its integration into SharePoint scenarios.

    For information on how to upgrade InfoPath 2007 forms with Person/Group Picker controls to InfoPath 2010, click here.

    Adding the Person/Group Picker to your form

    From the Controls Gallery on the Home tab or the Controls task pane, click the Person/Group Picker to insert it into the view.

    Controls Gallery

    Specifying a SharePoint site to query for people and groups

    The Person/Group Picker needs to connect to a SharePoint site to be able to function. Specify the SharePoint site as follows, unless you have already published the form to a SharePoint site, in which case that site will be used.

    1. Right-click the control in the view and select Person/Group Picker Properties from the context menu
    2. In the Person/Group Picker Properties dialog, select the SharePoint Server tab
    3. Type the URL of the SharePoint site you want to query

      Control Properties

    4. Click OK to close the dialog

    Specifying data validation (optional)

    In InfoPath 2010 it is now possible to mark the field the people picker is bound to as Cannot be blank. This means that users will not be able to submit a form without having entered at least one valid person or group in the control. You can mark a field as required by doing the following:

    1. Select the control in the view
    2. In the Properties tab in the Modify chunk, click the Cannot be blank checkbox

     

    PPickerCBB

    Testing the control

    Preview the form in InfoPath Designer or publish the form to a SharePoint site and view the form, enter a name or logon alias, click the “Check Names” button and resolve the name! Alternatively, you can click the “Address book” button to perform a search if you do not know the complete name of the user.

    For information on how to upgrade InfoPath 2007 forms with Person/Group Picker controls to InfoPath 2010, check out my other post here.

    Frank Mueller

    InfoPath Developer

  • Microsoft InfoPath 2010

    Submitting to a Database (via Web Services) in InfoPath Forms Services

    • 38 Comments

    If you've ever designed and deployed a form that will be frequently used or require significant data analysis, you have probably looked into maintaining data in a SQL database.  With InfoPath 2003 and the InfoPath 2007 rich client, you get what you expect.  You create a main database data connection to the SQL server and pick tables and columns that meet the requirements for submit functionality.  When you open your form and click the "Run Query" button, you see the data pulled from the database as you'd expect.  You then happily insert, update, or delete records and, when the time is right, hit "Submit".  Luckily for you, the InfoPath client took care of maintaining the list of changes that you made while editing your form.  With this list of changes intact, your updated data streaks back to the database to await the next query.

    Enter InfoPath Forms Server... Here we don't get the change tracking for free, so we'll need to do some work to simulate change tracking outside of the form's execution.  Basically, what we're going to try to accomplish is to use an intermediate web service that will handle querying and submitting the data from and to the target database.  The web service will timestamp the data at query time and send the data to the form for editing.  Then the form filling user will edit the data and click "Submit".  When the data arrives back at the web service, we need to figure out what changed in the meantime.  This means that we'll have to check to see if anything has changed in the database since the time when we queried the data.  If it has, then the submitted data should be rejected and the user should re-query before re-applying her edits.  If it hasn't, we'll diff the submitted data with the database data and submit the difference back to the database!  Let's get started!

     

    Create the Web Service and Setup the Database

    Since the InfoPath data connection wizard is easiest to use when your web service is already established and available, let's start with creating the web service and setting up the database.

    1) Download the attached archive and extract it somewhere on your hard drive

    2) Create a new web site in Internet Information Services (IIS)
    NOTE:  IIS must be enabled as a Windows Component through "Add or remove Windows components" in the "Control Panel")

    • Launch IIS ("Start" >> "Run", type 'inetmgr')
    • Right-click the "Web Sites" node and select "New" >> "Web Site…"
    • Click "Next >" on the first page of the wizard.
    • Type a name for your web site (e.g., "IPFSDiffGram") and click "Next >"
    • Type a unique port number (referred to, hereafter, as '<portNum>') for the web site and click "Next >"
    • Enter the path to a folder where the site contents will be stored and click "Next >"
    • Check "Read" and "Run scripts (such as ASP)" permissions and click "Next >"
    • Click "Finish".
    • You may want to create a new Application Pool for this web site "to make your server more efficient and reliable".

    3) Create the web service

    • Launch Visual Studio 2005.
    • Click "File" >> "New" >> "Web Site…"
    • Select "ASP.Net Web Service" in the "Visual Studio Installed Templates" section.
    • In the "Location" drop-down, select HTTP and then click "Browse…"
    • Select the Web Site created in step 1 and then click "Open"
    • Click "OK" on the "New Web Site" dialog

    4) Add the code and service asmx files to the project

    1. Open the Solution Explorer task pane (click "View" >> "Solution Explorer")
    2. Right-click the top-level project icon (labeled http://localhost:<portNum>) and select "Add Existing Item…"
    3. Navigate to the "DiffGramService.asmx" file and then click "Add". Refer to the files you downloaded for the contents of this file.
    4. Right-click the "App_Code" icon and select "Add Existing Item…"
    5. Navigate to the "DiffGramService.cs" file and then click "Add". Refer to the files you downloaded for the contents of this file.

    5) Customize the web service code for your database

    1. Instance variables
      1. DBConnectionString -- The connection string to connect to your database.
      2. DBTable -- The name of the table to which the web service should connect.  The table must feature a surrogate single-column primary key with an integer data type.
      3. ColumnNames -- An array that contains the names of the data columns in your database.
    2. WebMethod query parameters
      1. DBData(parameter_list)

        • parameter_list should be the columns, with appropriate System.Types to match your database
        • You'll need to specify the appropriate SqlDbTypes that correspond to the columns in your database
      2. UpdateDBData(DataSet, parameter_list)

        • Do not change the DataSet parameter
        • parameter_list should be the columns, with appropriate System.Types to match your database
        • You'll need to specify the appropriate SqlDbTypes that correspond to the columns in your database

    6) Create the database table and DML trigger
    The web service includes logic to update the database table and create a DML trigger to maintain a timestamp of Last Update for each record.  However, you may want to create the timestamp column and trigger yourself.

    • Example SQL script to create a database named "DBTable" that is compatible with this web service is in the attached files, named "CreateDBTable.sql". The table will have a structure similar to the following:

    • Example SQL script to create a DML trigger that will maintain the timestamp of last update for each record is also attached, and called "CreateDMLTrigger.sql".

    7) Build the Visual Studio solution and publish the web site

     

    Design the InfoPath Form Template

    Now that we've setup our database and constructed our web service to do the querying and submitting for us, it'll be a breeze to design an InfoPath form template based on the web service.

    1) Design a new, browser-enabled form template, based on the web service that will query/submit the DataSet.

    1. Launch InfoPath and select "Design a Form Template…" on the "Getting Started" dashboard dialog.
    2. Check "Enable browser-compatible features only" (required only for browser-enabled form templates)
    3. Select the "Web Service" icon and click "OK".
    4. Select "Receive and submit data" and click "Next >"
    5. Type the WSDL URL for your web service (e.g., http://<server>:<port>/DiffgramService.asmx?WSDL) and click "Next >"
    6. Select the web method that will return the DataSet and click "Next >".
    7. Click "Next >" on the DataSet change-tracking page.
    8. Click "Next >" to name the query data connection and move on to define the submit data connection.
    9. If the submit WSDL URL is different than the query WSDL URL, enter it here and click "Next >".  Else, just click "Next >".
    10. Select the web method to which the DataSet will be submitted and click "Next >".
    11. Select the DataSet parameter in the "Parameters" listView.
    12. In the "Parameter options" section, click the button next to the "Field or group" field.
    13. In the "Select a Field or Group" dialog that pops up, expand the "dataFields" node until you see the node with the name of the DataSet (it's the parent of the repeating "(Choice)" node).

       

    14. Select the DataSet node and click "OK"
    15. If your web service takes parameters to constrain the select command, map these parameters to the queryFields generated during the creation of the query connection.
    16. Click "Next >" on the submit parameter mapping page.
    17. Click "Finish" to name the submit data connection and finish the Data Connection Wizard.

     

    2) Set the default values for the "ID" and "QueryTime" fields

    1. In the InfoPath Designer window, click the "View" menu and select the "Data Source..." option.
    2. In the "Data Source" taskpane, expand the "dataFields" node completely.
    3. Double-click the "QueryTime" node to open the properties dialog.
    4. Type "1/1/1900 12:00:00 AM" (without the quotes) in the "Value" field in the "Default Value" section and click "OK"
    5. Repeat steps 2.a-2.c for the "ID" field.
    6. Type "-1" (without the quotes) in the "Value" field in the "Default Value" section and click "OK"

     

    3) Insert the controls into the View.

    1. Click inside the dataFields controls area (it says "Drag data fields here" if you haven't clicked there)
    2. Click the "Insert" menu and select the "Repeating Table..." option.
    3. In the "Repeating Table Binding" dialog, completely expand the "dataFields" node.
    4. Select the group node that has the same name as your database table and click "Next >"
    5. For each of your data columns (e.g., 'Column1', ..., 'Column5'), select the column name on the left, and then click the "Add >>" button to make the column show up in the Repeating Table.

      NOTE:  If you include the 'ID' column, the user will be able to edit the values, and the DataSet may not be validated or merged correctly.
    6. Click "Finish" to accept the repeating table binding and insert the repeating table into the View.

    4) Publish the form template to your InfoPath Forms Server

    At this point, you have a form template that will work correctly when you open it in the InfoPath rich client.  But this post is all about getting things to work correctly in the InfoPath Forms Server.  So you'll need to configure your data connections to work in the browser by converting the main query and submit data connections to use Universal Data Connection (UDC) files in a Data Connection Library (DCL).  Now you should be all set.  The web service will query and submit the data to the database, and we'll make our best attempt at a diff of the database data against the submitted data.

    From here on out, it's up to you.  If you want to, for example, modify the database structure or change the way the trigger works, then you're going to need to modify the web service code.  You'll also need to use "Convert Main Data Source" to update your form template whenever you modify your web service.  You might also want to add support for multiple tables.  All this will take some exploration of ADO.Net DataSets, but it is a reasonable exercise as long as you're comfortable writing managed code.

    Forrest Dillaway
    Software Design Engineer in Test

  • Microsoft InfoPath 2010

    Get the User Profile through MOSS Web Services

    • 37 Comments

    It is now easier than ever to pre-populate your InfoPath 2007 forms with the user profile information of the current user.

    Background:

    In Microsoft SharePoint Server 2003, the UserProfileService.GetUserProfileByName(string accountName) web service method required the caller to pass the account name (e.g., domain\alias) associated with the user profile to retrieve.  Though required, this argument was not needed when retrieving the profile of the current user.  After all, the form was running with the network credentials of the current user and those credentials were passed to the web service.

    The typical work-around was to deploy a custom WhoAmI web service as a façade for the UserProfileService.  This façade would provide a method (e.g., WhoAmI() ) that would detect the user's identity and effectively forward a call to the UserProfileService, returning the eventual result to the caller.

    New for Microsoft Office SharePoint Server 2007 and InfoPath 2007:

    In InfoPath 2007, you can get the logon name of the current user by just using a new built-in function; but what if you need to get more data than just the username? Manager name, phone number, office location, and other data are all accessible through the UserProfileService: read on.

    A form that uses the UserProfileService of MOSS to retrieve the User Profile of the current user no longer needs to explicitly pass the account information of the current user to the GetUserProfile method of the UserProfileService.  Simply passing a null value to this method will cause the web service to grab the user identity from the request.  The web service will then use that information as the account name and will subsequently return the User Profile of the current user.

    Use this technique when you want to pre-populate the fields of an InfoPath 2007 form with user information obtained from the MOSS 2007 User Profile Database. 

    The following instructions detail how to build a form to demonstrate this capability.

    Assumptions:

    • The default MOSS web application is configured to use Windows Authentication.
    • The MOSS server has an SSP with a User Profile Database that has been loaded from Active Directory
    • The end-user has a profile in the User Profile Database of the MOSS server
    • The end-user is logged into the client machine using his/her domain account.

     

    Step 1: Create the form

    1. Open InfoPath and design a new, blank form
    2. Save the form as UserProfileDemo.xsn

    Step 2: Design the form

    1. From the Layout Task Pane, add a 2 column x 4 row table to the form
    2. Place labels into the column 1 as follows: Name, Account, Email, and Phone
    3. Using the Controls Task Pane, drag four text box controls to your form, placing one in each row of column 2
    4. Using the Data Source Task Pane, rename the four "fieldX" data elements as follows: userName, userAccount, userEmail, and userPhone

     

    Step 3: Set the security level of the form

    1. From the Main Toolbar, select Tools | Form Options
    2. Select Security and Trust from the list box
    3. Clear the checkbox next to Automatically determine security level
    4. Select Full Trust
    5. Hit OK.

    Step 4: Add code to the form

    1. From the Main Toolbar, select Tools | Programming | Loading Event
    2. Right-click on UserProfileDemo node of the Project Explorer and choose Add Web Reference
    3. Enter the following for the URL: /_vti_bin/UserProfileService.asmx">http://<yourServerName>/_vti_bin/UserProfileService.asmx
    4. Enter the following for Web reference name: ProfileService
    5. Click Add Reference
    6. Replace the FormEvents_Loading event handler with the following code snippet:
    public void FormEvents_Loading(object sender, LoadingEventArgs e) {
    
        XPathNavigator myRoot = MainDataSource.CreateNavigator();
    
        ProfileService.UserProfileService profileService = new ProfileService.UserProfileService();
    
        ProfileService.UseDefaultCredentials = true;
    
        ProfileService.PropertyData[] userProps = null;
    
        try {
    
            // Passing null to this method causes the profile of the current user to be returned.
    
            userProps = profileService.GetUserProfileByName(null);
    
        }
    
        catch { }
    
        if (userProps == null || userProps.Length == 0) {
    
            return;
    
        }
    
        for (int i = 0; i < userProps.Length; i++) {
    
            XPathNavigator node = null;
    
            switch (userProps[i].Name.ToLower())  {
    
                // these property names can be obtained by reviewing the user profile properties in the MOSS SSP.
    
                case "preferredname":
    
                    node = myRoot.SelectSingleNode("/my:myFields/my:userName", NamespaceManager);
    
                    break;
    
                case "accountname":
    
                    node = myRoot.SelectSingleNode("/my:myFields/my:userAccount", NamespaceManager);
    
                    break;
    
                case "workemail":
    
                    node = myRoot.SelectSingleNode("/my:myFields/my:userEmail", NamespaceManager);
    
                    break;
    
                case "workphone":
    
                    node = myRoot.SelectSingleNode("/my:myFields/my:userPhone", NamespaceManager);
    
                    break;
    
                default:
    
                    continue;
    
            }
    
            ProfileService.ValueData[] values = userProps[i].Values;
    
            if (values.Length > 0) {
    
                if (node != null && string.IsNullOrEmpty(node.Value)) {
    
                    node.SetValue(values[0].Value.ToString());
    
                }
    
            }
    
        }
    
    }
    

     

    Step  5: Build and Preview

    1. Build the project and close VSTA.
    2. From the Main Toolbar, select File | Preview| Form
    3. When the form loads, the text boxes will be populated with your User Profile Information

    This example opens the door to simplifying the form submission process for your users by reducing the time they take to complete forms, as well as ensuring the accuracy of the data that they enter.

    Ronald Tielke
    Microsoft Consulting Services
    Desert Mountain District

  • Microsoft InfoPath 2010

    How to Pass Querystring data into an InfoPath Form

    • 35 Comments

    Hi there, Daniel Broekman here. After showing you how to customize a SharePoint list with InfoPath 2010, and describing the differences between SharePoint list forms and form library forms together with Kate Everitt, I’m back with a quick tip for easily sending  a value from the browser’s query string into an InfoPath form.

    Imagine one of the following scenarios:

    • You want to dynamically pull all the invoices for a specific customer into a single form. For example, you could have a link to http://server/site/ShowInvoices.aspx?Customer=Contoso, which could be set up to display a list of all the Contoso invoices in a table. If you then swap out “Contoso” with “Fabrikam” in the URL, you would see all of the Fabrikam invoices.
    • You want to track referrals for your form. You can do this by specifying a dynamic default value for the form indicating the referral source. For example, you can include a link to http://server/site/form.aspx?Referrer=Email in an email you send to users, and add a link to http://server/site/form.aspx?Referrer=Website on the homepage of your website, and capture the value of the “Referrer” parameter along with the rest of the form data.

    In InfoPath 2007, you could accomplish these scenarios with code. With InfoPath 2010 and SharePoint 2010, there is a much easier way to send data from the query string into an InfoPath form. Let’s take a look.

    The basic concept

    Using a web part page and a part-to-part connection between a Query String (URL) Filter web part and an InfoPath Form Web Part (new in SharePoint 2010), we can easily pass a value from the browser’s query string into the form.

    Step-by-step

    I’m going to assume you already have a list form published to SharePoint. I just created a simple form to collect feedback on a conference presentation. As you can see, I included a “Referrer” field that will track the referral source of users filling out my form.

    Conference Feedback Form

    To set up the rest of the scenario, follow these steps:

    1. Create a new web part page.
    2. Add 2 web parts to the page. From the “Forms” category, add the InfoPath Form Web Part, and from the “Filters” category, add the Query String (URL) Filter web part. Web Part Adder (Forms Category)Web Part Adder (Filters Category)
    3. Configure the InfoPath Form Web Part to point to the list or library where your form is published. InfoPath Web Part Tool Pane
    4. Configure the Query String (URL) Filter web part to specify the parameter name it should look for in the URL. In this case, we want it to find “Referrer”. Query String Web Part Tool Pane
    5. Next, set up the part-to-part connection by opening the Web Part edit menu and selecting Connections > Send Filter Values To > InfoPath Form Web Part. Query String Web Part Connection Menu
    6. This brings up a dialog where you can choose the field in the form where the data should be sent. Choose the field you want, and then click Finish. In this case, we want to map the data to the “Referrer” field. Web Part Connection Dialog

    Everything should be set up correctly now. Save your changes to this page, and then navigate to the page. You should see the blank form.

    Saved Web Part Page

    Testing the Connection

    To test that everything is working correctly, add “?Referrer=email” to the end of the URL, and you should see the Referrer field being populated with the value “email”.

    Testing the Query Parameter Connection

    That’s it! You now have a page that passes data from the query string into an InfoPath form, set up in less than 5 minutes, and without any code.

    For more advanced scenarios, you can use this as a starting point. For example, you could have a rule on the “Referrer” field that performs certain actions based on the incoming value, such as querying a secondary data source, loading a specific item, etc. In the “customer invoice” example I gave at the beginning of this post, you could have an “onchange” rule on the “Customer” field that queries a secondary data connection for all of that customer’s invoices.

    One final note: the InfoPath Form Web Part only supports one incoming part-to-part connection at a time, which means that you are limited to passing one value into the form using this method.

    Please leave a comment to let me know how you’re using this functionality in your forms!

    Daniel Broekman

    Program Manager – Microsoft InfoPath

  • Microsoft InfoPath 2010

    Digital Signature Support in InfoPath 2010

    • 32 Comments

    Hi, this is Gergely Kota, a developer on the InfoPath team. Digitally signing data when filling out a form makes the data tamper-proof, authenticates its signer, and is a key component of trusting form data. In this post, I’d like to share the improvements that have been made to digital signature support in InfoPath 2010. InfoPath 2010 allows you to make more secure signatures with improved cryptographic algorithms and makes long-term storage of signed forms more robust by supporting 3rd-party time stamping. This post describes these improvements and shows you how to strengthen any signature created in InfoPath 2010 Filler. For a primer on digital signatures, read an Introduction to Digital Signatures in InfoPath.

    Note - Data signing should not be confused with code/template signing, which remains unchanged.

    Signature Security

    Digital signatures are only as secure as the cryptographic algorithms they use to ensure signed data hasn't been tampered with. InfoPath 2007 and 2003 support RSA or DSA for signing and SHA1 for hashing. Though a combination of RSA and SHA1 is considered secure for now, algorithms become exposed to attack over time and are eventually rendered obsolete. If either the signing or hashing algorithm is cracked or compromised, the integrity of the signature can no longer be verified. InfoPath 2010 enables you to address these concerns by supporting newer, more secure, ECC signing and SHA-2 family of hashing algorithms.

    Signing with a particular algorithm

    When creating a signature, a user may sign with one of potentially many certificates installed on their machine. The signature algorithm is determined by the chosen digital certificate. To determine the algorithm:

    1. Begin the signing process Clickhere to sign
    2. Change your signing certificate ChangeCert
    3. Highlight desired certificate and click View Certificate 
    4. Look at the Public key field under the Details tab Viewcert

    Administrator Settings: Hashing algorithms

    By default, InfoPath 2010 hashes signature data using SHA1. This is done to maintain backwards compatibility with InfoPath 2007 and InfoPath 2003. InfoPath 2010 also supports the SHA2 family of hashing algorithms. If backwards compatibility is not a concern, an administrator can set the hashing algorithm in the registry.

    HKCU\Software\Microsoft\Office\14.0\Common\Signatures\SignatureHashAlg
    Value Description
    “sha1” (default) SHA1 hash algorithm
    “sha256” SHA256 hash algorithm
    “sha384” SHA384 hash algorithm
    “sha512” SHA512 hash algorithm

    Signing and Hashing Algorithm Compatibility

    The following table shows which versions of InfoPath are able to sign and/or verify signatures with the given combinations of signing and hashing algorithms:

    DigSigAlgoSupportMatrix

    Long-term Signature Support

    Certificates guarantee the identity of the signer, but expire after a while. This is to reduce the time attackers have to deduce an associated private key (which would allow them to impersonate a signer) and to limit the shelf-life of a compromised certificate. Certificates may also be revoked if they are taken out of commission before their expiration date. If the certificate used to create a signature is now expired or revoked, we should be cautious of whether the signed data is valid or not unless we can verify that the data was signed while the certificate was still valid. This poses an impending problem because all certificates expire (often in a year!), and we would require a trusted timestamp to confirm when the signature was created. Without such a trusted timestamp, InfoPath will show the signature as invalid, with the reason in the Signature Details dialog:

    InvalidSignature

    sigdetails_full_expired

    This can be especially problematic, for example, for a printed copy of the form which would show an invalid signature, and there would be no way to verify why. InfoPath 2010 adds support for XML Advanced Electronic Signature (XAdES), which allows for adding a trusted timestamp that can be used to resolve when the signature was added relative to the signing certificate's expiration and/or revocation time (see a detailed discussion of XAdES in Microsoft Office for details and level options). If such a timestamp exists and confirms that the signature was made when the signing certificate was valid, InfoPath can safely conclude that the signature is entirely valid:

    ValidSignature

    sigdetails_full_good

    Server Support

    InfoPath 2010 Forms Services signs forms using RSA and SHA1, and is able to verify any signature created in the InfoPath 2010 client. XAdES is a client-only feature.

    Final Word

    By leveraging the security improvements and time-stamping support described in this post, you are increasing the strength and longevity of your signatures. Happy signing!

    Gergely, InfoPath dev

  • Microsoft InfoPath 2010

    Comparing SharePoint List and Form Library Forms

    • 31 Comments

    So you’ve heard about SharePoint list form customization in InfoPath 2010 and you’ve seen the cool demos. But you may be asking yourself – What’s the difference between list and library forms and when should I use one or the other? In this post, we will answer these questions and provide guidance on when to create list vs. library forms.

    When designing InfoPath forms for SharePoint 2010, the first choice you need to make is between a SharePoint list form and a SharePoint form library form.

    Popular Form Templates

    Recommendation

    Use a list form if you just need to collect data and store it on SharePoint. Use a form library form if you want more advanced functionality such as complex or repeating data or code.

    What are list forms and form library forms?

    SharePoint list forms store data directly in a SharePoint list.  Each control (e.g. text box) in the form is bound to a column in the list. SharePoint list forms are directly connected to the list, which means that you don’t have to worry about setting up the publish and submit locations.
    Form library forms store data in XML files in a SharePoint form library. This means they are more flexible and you can do more with them. For example, they can be configured to save drafts and submit to different locations. However, they are more complex to work with and require more decisions to be made during configuration.

    Because the way data is stored between these template types is different, it is not possible to switch between them.

    Guidelines

    Here are some basic guidelines to help you decide what type of form to design.

    Use a list if:

    • You want to quickly get started building InfoPath forms on SharePoint
    • You need to use your form offline with SharePoint Workspace (formerly Groove)
    • You want to filter your SharePoint list based on a person or group
    • You would like to use the built-in display / edit views

    Use a form library if:

    • You have repeating or nested data
    • You are working from a predefined industry or complex schema
    • Your form needs to be digitally signed
    • You need code in your form
    • Your form is not hosted in SharePoint or you need to store results as an XML document

    How can I build advanced functionality into my forms?

    In general, form libraries provide better support for more complex and advanced forms. Here are a few examples of the way InfoPath can be used to build more powerful forms.

    Repeating data or complex schema

    • In some cases, you will want to collect repeating data in a form. For example, you have a project proposal form and want to include a list of potential risks for each project, or you have a book request form where users can request multiple books at once.
    • If you have a schema that has any nesting or repeating structures, or a defined industry schema such as Dublin core or Health Level 7, form library forms will allow you to organize your fields into groups to match your schema as opposed to having to flatten your schema to work with a list.
    • SharePoint lists store only one value per column; you can’t use list forms to store repeating data in a single item. As form library forms use XML to store data they can store repeating data in a single form.

    Using repeating data in list forms

    • If you have a SharePoint list form, you have several options for dealing with repeating data other than using the built in support of a form library.
    • If part of your content is repeating, consider flattening that schema so that it can repeat. For example, you could limit your book request form to no more than ten books per form.
    • You can also use multiple lists and link them together using lookup fields and web part connections. This works well for master/detail scenarios where one list tracks all the items and another contains the specific details for each item.

    Using repeating data in form library forms

    • Form library forms include controls that are designed to deal with repeating data inside the current item.  Form libraries have built-in support for repeating data with controls such as plain list, bulleted list, numbered list, repeating table, and repeating section.
    • They also support more customization of the form using the choice group and choice section controls. Advanced choice controls such as option button and optional sections are also available. All of these controls will be available by default in the controls gallery in InfoPath Designer for form library forms.

    Digital Signatures

    Managed Code

    • Form libraries support code-behind. This will allow you to do actions beyond logic in your form, such as advanced financial calculations.
    • Code can be used to extend InfoPath functionality or create custom business logic.
    • For example, in a pet food store you may use an InfoPath form to track food orders and use code behind the scenes to make sure you have enough inventory to meet the order and make sure that it isn’t sold before the form is submitted.
    • For more detail about forms with code, see Introduction to Programming in InfoPath 2010.

    Control over where your form is stored

    • Form libraries allow you to choose the location of where your form XML is sent when the form is submitted.
    • If you need to store your form as an XML document for use outside of SharePoint, then you should use a form library.
    • For example, if you have an insurance questionnaire and you want to store the completed form in a document collection with related content, a form library will allow you to do this.

    Bottom line

    Overall, both list forms and form library forms support much of the key functionality that InfoPath provides, such as data validation, custom rules, default values, and control over visual layout. In most cases, a list form will be sufficient for your needs. Lists have the most straightforward design and form management experience. However, for more complex scenarios such as repeating data or the need to add code, a form library may be necessary.

    Please leave a comment if you have any further questions!

    Daniel Broekman and Kate Everitt

    InfoPath Program Managers

  • Microsoft InfoPath 2010

    SharePoint List Data Connections in InfoPath 2010

    • 30 Comments

    Hi, my name is Joey Wiggs and I’m a developer on the InfoPath team. In InfoPath 2010, one of the ways in which we've improved our integration with SharePoint Server 2010 is by providing richer capabilities for connecting to and getting data from SharePoint lists. In this post, I will compare SharePoint list data connections in InfoPath 2007 and InfoPath 2010, and discuss the benefits of using the new 2010 data connection type. I will also outline the steps required to upgrade your InfoPath 2007 SharePoint list data connections to the new and improved version.

    About SharePoint List Data Connections

    Let’s start by looking at a scenario when you would use a SharePoint list data connection in an InfoPath form.

    In Microsoft, when employees run into technical issues, they log a help ticket by filling out an InfoPath form. They start filling out the form by selecting an Problem category from a dropdown list. We could store the category names inside the form but that means that whenever a category is added, deleted or renamed, the form will need to be updated.

    Help Request Form

    Instead, we can store the Category names in a separate SharePoint list and pull this information into the form when users are filling it out. We can do this by adding a SharePoint list data connection to the form. The benefit of using a data connection is that the data can be maintained separately in a single location and the form will always pull in the most up to date information from that location.

    Why use the 2010 SharePoint List Data Connection?

    In InfoPath 2010, we have extended the functionality of the SharePoint list data connection.
    • Query fields are now supported
    • Additional field types are supported
    • The data pulled from the SharePoint list is no longer tied to the default list view in SharePoint

    Query Fields

    Setting a query field value allows you to filter the data before it is pulled into the form. SharePoint list connections in InfoPath 2010 now have query fields, allowing you to filter your data and return more scoped results. You can query on a number of different field types, including single lines of text, numbers, and even people and lookups. By filtering your list connections, you can ensure only the data you want is brought into your form. This can also speed up your form connection, as it may pull in less data than it would otherwise.

    For example: By setting the “Modified by” query field to the current user (using the username() function), the query will return only those list items that were modified by the current user.

    Fields Task Pane

    Additional Field Types

    In 2007 the list connection could only support simple field types, such as single lines of text, currency fields, and single choices. The new connection now also supports complex field types such as multiple choices, multiple lookups, attachments and person fields.

    Sorting results

    In previous releases, the number of items returned and the sorting order of said items were determined by the default view for the list in SharePoint. To work around this limitation, form designers had to go to the list settings page in SharePoint and modify the default list view to get the data they wanted into their forms. That’s no longer the case! The new 2010 list data connection will return all of the items in the list, regardless of the default view’s settings. You can also sort the incoming data by a particular field in the data connection wizard when creating a new connection, or modifying an existing one.

    Data Connection Wizard

    How can I get this in my forms?

    If you’re designing a new InfoPath 2010 form, you just need to add a SharePoint list data connection and you’ll have this functionality available to you from the start.

    The new list features are supported in InfoPath 2010 filler and browser forms only, so if you want to use the new connection in your existing InfoPath 2007 form you will need to upgrade your existing forms to InfoPath 2010. However, once upgraded, InfoPath 2007 clients will not be able to open the form.

    To upgrade the data connection, form designers must complete the following steps:

    1. Use the data connections dialog to upgrade the list connection
    2. Rebind your controls, rules and code
    3. Save the form as an InfoPath Web Browser Form Template or InfoPath Filler Form Template

    Data Connection Wizard

    Convert Data Connection to Current Version

    For each list data connection that retrieves data in your form, you will need to select it in the data connections dialog and press the “Convert to Current Version” button. You will be prompted if you want to continue. After conversion, you will see an information bar when that connection is selected stating that the data connection is incompatible with the current version of your form. That’s okay; we’ll be upgrading the form to the required version later.

    Data Connection Wizard

    Rebind Controls and Fix up Rules and Code

    After converting a data connection, you’ll need to rebind your controls and fix any field or XPath references inside rules and code. When rebinding, you’ll need to rebind the repeating sections to the d:SharePointListItem_RW group, then rebind the controls inside the repeating sections to the correct fields. You can rebind a control by selecting it, then right-clicking and choosing “Change Binding”. This brings up a dialog where you can choose what field or group to bind the control to.

    Control Binding

    Fixing your rules consists of finding the rule and updating any field references. Field references from the old adapter will look something like “@Title” after you convert your 2007 adapter to 2010. Select the reference, pick the field you want the rule to reference and away you go.

    Rule Fix up
    You can tell that the rule actually references the field by how it looks. If the field reference has a namespace, an @ symbol, or a full XPath then that rule won’t work and needs to be fixed.

    Save the Form

    Finally, you’ll want to save your form as an InfoPath form template (filler or web browser depending on your needs). Note that if you try to save it before converting the data connections, the design checker will prevent you from doing so. 2007 list data connections cannot be in a 2010 form, and 2010 list data connections cannot be in a 2007 form. There’s no mixing and matching, and the design checker will prevent you from saving the form unless they’re correct.

    Once you’ve saved your form, you will be able to avail of all the capabilities of the new 2010 SharePoint list data connection. At any time, you can use the data connections dialog to modify the newly upgraded connection, to add new field types, or to use the sort by functionality. You can also set the value of query fields using rules in your form.


    Enjoy!

    Joey Wiggs

    InfoPath Developer

  • Microsoft InfoPath 2010

    Introduction to Programming in InfoPath 2010

    • 29 Comments

    Hello, my name is Christopher Brotsos, and I’m a Program Manager on the InfoPath team. In this post, I’m going to show you how to add business logic to your forms using managed code.

    Imagine a scenario where the accounting department at Contoso, Inc. tracks corporate assets through an Asset Management System built on SharePoint. One module in the system allows employees to order office equipment such as laptops, conference phones, and ergonomic chairs through an InfoPath form. At first, the order form was built using only declarative logic. It could enforce required fields, surface validation messages, and submit the form to SharePoint without any code.

    As the ordering process grew more complex, users started adding additional requirements to the system. The variety of inventory available to employees increased, so they wanted a way sort items by name and description real-time in the order form. Contoso also started shipping their office equipment out of three warehouses. This prevented the warehouse crew from fulfilling complete orders, and as such, the system needed to track shipping status and quantity of individual items in the order. To meet the new requirements, Contoso added the following features to the form:

    • A custom sort interface
    • Logic for managing complex data when the form is submitted
    • Logic to add items to a SharePoint list

    Sort interfaces, sophisticated submit routines, and database (i.e. list) management are common requirements for forms. Fortunately, this functionality can be added to InfoPath forms with a few lines of code. Let me explain these features, the code required to build them, and the prerequisites for developing managed code in InfoPath in more detail.

    Equipment Request Form

    The employee orders module in the Asset Management system consists of three core components:
    1. A SharePoint form library, “Equipment Orders”, where users go to fill out the Equipment Order Request form shown below.
    2. A SharePoint list, “Equipment Inventory”, which stores the items available for users to order. This list contains fields specifying items’ names, descriptions, and quantities used to populate the Equipment Order Request form.
    3. A SharePoint list, “Equipment Shipping”, which stores a list of items ordered by users that have been scheduled for shipping. This list contains fields for the names and quantities of items being ordered as well as the name of the user who placed the order.

    The Equipment Request Form enables users to sort through Contoso’s available inventory and submit a request to the warehouse for shipping.

    Equipment Order Request Form

    The order form is a repeating table, where each row in the table represents the name, description, and quantity of the item being ordered.

    Equipment Order Request Form 

    Sorting data in the form

    The Equipment Order Form has a Picture Button Control displaying an arrow next to each of the column labels.

    Equipment Order Request Form

    The buttons are used to sort the order items in ascending order by the respective column. When the user clicks the button, the values in the selected column are compared, and the rows of data are sorted based on the comparison result.

    The sorting routine in this example is based on a complete solution provided by Hagen Green. Read through his post to learn how to provide a descending sort which also takes localization and data types into consideration.

    private string GetValue(string xpath)
    
    {
    
      // return the value of the specified node
    
      XPathNavigator myNav = this.MainDataSource.CreateNavigator().SelectSingleNode(xpath, NamespaceManager);
    
      if (myNav != null)
    
        return myNav.Value;
    
      else
    
        return "";
    
    }
    
    private void Swap(string xpath1, string xpath2)
    
    {
    
      // swap two rows of the table 
    
      XPathNavigator item1 = this.MainDataSource.CreateNavigator().SelectSingleNode(xpath1, NamespaceManager);
    
      XPathNavigator item2 = this.MainDataSource.CreateNavigator().SelectSingleNode(xpath2, NamespaceManager);
    
      if (item1 != null && item2 != null)
    
      {
    
        // Make a copy of item1
    
        // Move item2 to item1
    
        // Make the original item2 be item1 that we cloned earlier
    
                    
    
        XPathNavigator item1Clone = item1.Clone();
    
        item1.ReplaceSelf(item2);
    
        item2.ReplaceSelf(item1Clone);
    
      }
    
    }
    
    private void SortOrder(string sortBy)
    
    {
    
      string itemsToSort = "/my:myFields/my:Order/my:OrderItem";
    
      XPathNodeIterator items = this.MainDataSource.CreateNavigator().Select(itemsToSort, NamespaceManager);
    
      if (items != null)
    
      {
    
        int numItems = items.Count;
    
        // basic bubble sort implementation
    
        for (int i = 1; i < numItems; i++) // xpath is 1-based
    
        {
    
          for (int j = i + 1; j <= numItems; j++)
    
          {
    
            // swap (i,j) if necessary
    
            string iValue = GetValue(itemsToSort + "[" + i + "]" + sortBy);
    
            string jValue = GetValue(itemsToSort + "[" + j + "]" + sortBy);
    
            if (String.Compare(iValue, jValue, true) > 0)                       
    
              Swap(itemsToSort + "[" + i + "]", itemsToSort + "[" + j + "]");
    
                            
    
          }
    
        }
    
      }
    
    }
    
    public void ItemNameSort_Clicked(object sender, ClickedEventArgs e)
    
    {
    
      // Sort order by ItemName
    
      // Repeat this code for the other buttons
    
      string sortBy = "/my:ItemName";
    
      SortOrder(sortBy);
    
    }
    

    Managing complex data during submit and updating SharePoint lists using the SharePoint object model

    The user is eventually going to finish selecting items and submit the order. Each item ordered through the form is handled independently because, for example, an item in the order may be delayed or shipped from a remote warehouse. So, we need submit logic which will break up the complex data (i.e. the repeating table of items being ordered) into individual rows, and add a shipping request to the Equipment Shipping list for each item-quantity pair. After an item is added to the Equipment Shipping list, a SharePoint workflow is used to track status and manage the Inventory Equipment list’s quantity values.
    1. The first thing you’ll need to do is use the Submit Options button on the Data tab in the ribbon to add a custom submit handler to your VSTA project.

      Submit Options

    2. Add a reference to Microsoft.SharePoint.dll to your VSTA project. This will allow you to develop code using the SharePoint object model. This DLL is installed in %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\14\ISAPI with your licensed copy of Microsoft SharePoint Server.
    3. Add custom submit logic to create a SharePoint list item for each item in the order form. See the code below for an example, and notice the use of the ServerInfo class. The ServerInfo class is new to InfoPath 2010 and allows you to write portable code with relative references to SharePoint server URLs.

     

    public void FormEvents_Submit(object sender, SubmitEventArgs e)
    
    {
    
      // Loop through each item-quantity pair in the order form.
    
      // Submit pairs to the Equipment Shipping list.
    
      // Note: Workflow will handle updating item quantities and track shipping status.
    
      using (SPSite mySite = new SPSite(ServerInfo.SharePointSiteUrl.ToString()))
    
      {
    
        using (SPWeb myWeb = mySite.OpenWeb())
    
        {
    
          XPathNodeIterator orderItems;
    
          if (myWeb != null && myWeb.Lists["Equipment Shipping"] != null)
    
          {
    
            SPList shippingList = myWeb.Lists["Equipment Shipping"];
    
            myWeb.AllowUnsafeUpdates = true;
    
            orderItems = this.MainDataSource.CreateNavigator().Select("/my:myFields/my:Order/my:OrderItem", NamespaceManager);
    
            if (orderItems != null)
    
            {
    
              while (orderItems.MoveNext())
    
              {
    
                // Add rows from the form where user selected an item and specified a quantity.
    
                string itemName = orderItems.Current.SelectSingleNode("./my:ItemName", NamespaceManager).Value;
    
                string itemQuantity = orderItems.Current.SelectSingleNode("./my:ItemQuantity", NamespaceManager).Value;
    
                if (itemName != string.Empty && itemQuantity != string.Empty)
    
                {
    
                  SPListItem shipItem = shippingList.AddItem();
    
                  shipItem["Title"] = itemName;
    
                  shipItem["Quantity"] = itemQuantity;
    
                  shipItem.Update();
    
                }
    
              }
    
            }
    
          //cleanup
    
          //signal successful submit
    
          //return
    
          myWeb.AllowUnsafeUpdates = false;
    
          e.CancelableArgs.Cancel = false;
    
          return;
    
          }
    
        }
    
      }
    
    }
    

    Along with the features covered above, you’ll find that code is useful for implementing complex data validation logic and managing content from multiple data sources. Such requirements are especially common when your forms are part of an advanced application. You can learn more about validation and working with the InfoPath DOM in our MSDN XmlEvent.Validating documentation and our post on working with InfoPath data sources programmatically. You can also review the InfoPath and SharePoint object models on MSDN for a more granular view into programming with InfoPath 2010.

    If you’d like to get started with programming in InfoPath, then please read on. The rest of this post introduces our system requirements, integrated development environment, and programmability user experience.

    How to add code to an InfoPath form

    To add code to an InfoPath form:

    1. Make sure you meet the minimum system requirements.
    2. Install Visual Studio Tools for Applications (VSTA).
    3. Choose a programming language.
    4. Add event handlers and code.

    Minimum system requirements

    The minimum system requirement to get started with InfoPath 2010 development is Microsoft .NET Framework 2.0, but we suggest you install Microsoft .NET Framework 3.5 SP1 if you’re developing for the SharePoint platform. You can install all versions of Microsoft .NET Framework from http://www.microsoft.com/downloads.

    Installing Visual Studio Tools for Applications

    Visual Studio Tools for Applications (VSTA) is an optional installation component available in Microsoft Office 2010 setup. To install VSTA:

    1. Launch Office 2010 setup from your Office 2010 installation media or from the Control Panel Programs and Features application.
    2. If you’re installing a new copy of Office 2010, click the Customize button in the installer. If you’ve already installed Office 2010, choose the Add or Remove Features radio button in the installer.
    3. Set the Visual Studio Tools for Applications option to Run from My Computer and continue through the setup wizard.

    Office Setup

    Choosing a programming language

    InfoPath 2010 allows you to program in C# and Visual Basic .NET. If you want to program with Visual Basic, you do not need to do anything to select your programming language when designing InfoPath 2010 compatible forms. If you plan on programming with C#, or adding code to InfoPath 2007/2003 compatible forms, you can change the programming language by clicking the Language button in the Code group of the Developer tab.

    Developer Tab

    After you click the Language button, you can change your programming language by using the Form template code language drop down:

    Form Options

    Hint: You can change the default language for InfoPath 2010 compatible forms by using the Options menu in the Backstage.

    1. Click the File > Options tab
    2. Click the More Options button in the General category of the InfoPath Options dialog
    3. Change the Programming language dropdowns in the Programming Defaults section of the Design Options

    Options

    Adding event handlers

    The Developer tab is the primary entry point for programming in InfoPath 2010. It’s designed to help you add event handlers compatible with the controls and mode of the form you are designing. For example, if you don’t have a control selected on your form view, then you’ll only be able to select the events that apply to the entire form. Notice that the Loading and View Switched event below are enabled, but the entire Control Events group is disabled.

    Developer Tab

    But, as soon as I select a text box on the form, the Control Events group lights up.

    Developer Tab

    Notice that the Sign, Context Changed, and Changing events are disabled in both screenshots of the Developer tab. That’s because I’m working with a browser compatible form, and those events are only available for InfoPath Filler forms.

    Note: You’ll find a table of all events, and their compatibility, towards the end of this section.

    Certain control and form programming events can be accessed through buttons on other tabs in the ribbon. If you add a Picture Button control on the form view, highlight the button, and then click on the Properties tab then you’ll find the Custom Code button enabled. Clicking the Custom Code button in the ribbon will add an OnClick event for the Picture Button control.

    Custom Code Button

    In the Equipment Order Request form, we added a Submit event handler to add items to a SharePoint list. To do this, navigate to the Data tab, and click the Submit Options button in the Submit Form group.

    Submit Options Button

    This will launch the Submit Options dialog where you can check “Allow users to submit this form”, “Perform custom action using Code”, and then click the Edit Code button.

    Submit Options

    The Fields task pane is another main entry point to add event handlers. In the next screenshot, I access the Validating and Changed events for ItemDescription by right clicking the field in the Fields task pane and scrolling through its context menu.

    Fields Taskpane

    The following tables provide a list of all events and compatibility in InfoPath 2010. Note that InfoPath forms trigger three types of events: Form Events, Data Events, and Button Events. Aside from the button event, InfoPath event handling is different from other web programming paradigms (e.g. WinForm and HTML forms); events are fired when the data changes, not when control state changes. As such, you should consider the optimal configuration for your forms’ post-back settings to provide the best performance while still ensuring that events get fired when necessary. See our performance post on MSDN to learn more about general performance and event handler post-backs.

    Tables

    After you’ve designed your form and authored the source code, the final step is to publish the form. Your InfoPath form with code can be published to SharePoint and to client machines, but you need to make a security decision before you publish: configure the form as domain trust or full trust.

     

    Domain trust forms can be published to SharePoint as Sandboxed Solutions directly from the InfoPath 2010 Designer. With Sandboxed Solutions, SharePoint Server farm administrators can restrict the resources available to the code and developers cannot access resources subject to operating system security. This establishes a safe environment where Site Collection administrators can publish code to SharePoint without the overhead of administrator approval! For more details about Sandbox Solutions (and another method for sorting repeating tabular data), see our Introduction to Sandboxed Solutions post from Phil Newman.

    Note: Publishing full trust forms to a client-side environment requires that the form is signed with a code-signing certificate or installed through a custom MSI built in Visual Studio. Publishing a full trust form to SharePoint requires a farm administrator to activate the solution through the SharePoint Central Administration portal.

    Best Practice: You should always use the lowest level of trust possible when publishing forms.

    Summary

    Most forms you design with InfoPath 2010 are not going to require code, but when they do, just install Visual Studio Tools for Applications and you’re ready to start programming. To add code, select the language of your choice, and use entry points in the Ribbon and Fields task pane to automatically insert event handlers. Finally, decide whether or not your form requires full-trust, and publish it to SharePoint or a client environment accordingly. If you’re interested in learning more about the InfoPath and SharePoint programmability, please visit http://www.msdn.com and keep checking for updates here on the InfoPath blog.

  • Microsoft InfoPath 2010

    Customize a SharePoint List Form using InfoPath 2010

    • 29 Comments

    Today sees the launch of our new "5 for forms" video demo series. In this series, we will demo a cool new InfoPath 2010 feature or scenario in less than 5 minutes.

    In the 1st video of the series, Daniel Broekman, a program manager on the InfoPath team will show you how you can customize a SharePoint list form with just a few clicks:

    Get Microsoft Silverlight

    We will post the next video in the series "Create tabs using Picture buttons"  after the holidays on January 7th.

    Enjoy!

  • Microsoft InfoPath 2010

    Passing Data into a Form: Input Parameters

    • 29 Comments

    This blog article discusses a new feature of Microsoft InfoPath 2007 that makes it possible to pass data into an InfoPath form at load time. A typical example would be retrieving records from a database for a particular user. At load time a ‘userID’ can be passed into the form. This userID can then be used to query the database and load the form with the user's data.

    Parameters can be passed into InfoPath form templates (XSNs) or InfoPath Forms (XMLs). The syntax for specifying input parameters is the same for both. This article focuses primarily on InfoPath client scenarios, but should apply for the most part to server scenarios as well.

    How to Pass Parameters into an InfoPath Form:

    There are two ways of launching an InfoPath form with parameters

    1) URL

    The syntax for passing parameters via the URL is the standard syntax for query parameters. For example:

    http://www.foo.com/bar.xsn?baz=1&biz=2

    Here two input parameters have been passed into the form namely 'baz' and 'biz'. Their respective values are 1 and 2. The 'Accessing Input Parameters in Form Code' section talks about how these values are stored and accessed in InfoPath code.

    The URL syntax can be used in a number of places like

    • Launching an InfoPath form in a browser by typing the URL into the address bar
    • Pasting the URL to a form or a form template into an email
    • Using the URL inside methods like NewFromFormTemplate, New, Open (XmlForms collection)
    2) Command Line

    The syntax for passing parameters via the command line is as follows:

    infopath.exe “C:\foo\bar.xml” /InputParameters "baz=1&biz=2"

    The switch /InputParameters is used to specify that parameters are being passed into the form, followed by the name/value pairs of input parameters.

    Accessing Input Parameters in Form Code

    Parameters passed into an InfoPath form template or form, are available during the Loading event as a read-only collection of name/value pairs. In order to access these parameters you will need to write code that reads from this collection. The InputParameters collection is exposed in all three InfoPath programming models – it is thus available in JScript, InfoPath 2003 SP1 managed code or InfoPath 2007 managed code. This example uses C# and the InfoPath 2007 managed object model. Syntax for the legacy models follows. The steps below outline how to add code that access the Input Parameters passed into a form.

    1. In the InfoPath designer, click on Tools menu -> Programming menu item.
    2. In the fly-out menu select the Loading event (will be On Load in older InfoPath versions).
    3. This will launch the appropriate IDE (MSE or VSTA or the Visual Studio Toolkit) with the code spit for the loading event inserted.
    4. Add the following code to access the input parameters ‘baz and ‘biz used in the examples above (example is in C# using InfoPath 2007 Managed Object Model)

    public void FormEvents_Loading(object sender, LoadingEventArgs e)

    {

       // Assign the value of the parameter 'baz' to the string 'bazValue'. bazValue = 1

       string bazValue = e.InputParameters["baz"];

     

       // Assign the value of the parameter 'biz' to the string 'bizValue'. bi000zValue = 1

       string bizValue = e.InputParameters["biz"];

     

       // Code that uses the parameters passed in to do whatever needs to be done

       // Example would be to create a custom query using these values and populate a table based

       // on the data returned
    }

    Input Parameter Syntax for Legacy Object models

    The following two code samples contain code for the InfoPath 2003 SP1 Managed Object Model (C#) and Jscript (InfoPath 2003 Object Model)

    1) C# InfoPath 2003 SP1

    In the InfoPath 2003 SP1 Object Model the InputParameters collection is exposed off the XDocument object not off the eventArgs object. Also since this is a new feature the XDocument object needs to be cast to the newer _XDocument3 interface to get access to the InputParameters collection. Hence the first line of code in the sample below.

     [InfoPathEventHandler(EventType = InfoPathEventType.OnLoad)]

     public void FormEvents_OnLoad(DocReturnEvent e)

     {
        
    // Cast XDocument to _XDocument3 to get access to the InputParameters collection
        
    _XDocument3 infopath2007XDocument = (_XDocument3)e.XDocument;

         string bazValue = infopath2007XDocument.InputParameters["baz"].Value;

         string bizValue = infopath2007XDocument.InputParameters["biz"].Value;

     }

    2) JScript

    function XDocument::OnLoad(eventObj)
    {
          var bazValue = eventObj.XDocument.InputParameters["baz"].Value;
          eventObj.XDocument.UI.Alert(bazValue);
    }

    Help

    Comprehensive documentation and additional code samples for this feature can be found under MSE Help or VSTA Help.

    Aditi Desai
    Software Design Engineer in Test

  • Microsoft InfoPath 2010

    Cascading Dropdowns in Browser Forms

    • 29 Comments
    If you are building an InfoPath client-only solution and you need to filter drop-down list boxes, you can simply use the “Filter Data” feature when you set the Entries property for the control. However, since filters are not supported in browser-compatible form templates, how can you accomplish the same functionality?
     
    This is where .NET web services can “save the day!” By creating web methods that accept parameters, you can add those web methods as data connections and then pass the selected value from one drop-down list box to the appropriate data connection “queryField”. Once the queryField has been set, simply execute that data connection to retrieve the associated values.
     
    To setup this sample, you will need to have access to the SQL Server Northwind sample database and Visual Studio installed on your server.
     
    First, let’s create the web service and the two web methods we will use in this sample:
     
    Step 1: Open the appropriate web site
     
    1. Launch Visual Studio
    2. From the File menu, select Open and choose Web Site
    3. Select File System and then navigate to: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS
     
    NOTE: By choosing to open the LAYOUTS folder, your web service will be available from all provisioned sites. If you want the web service only to be available from a specific site (i.e. the default site) you would want to open: C:\Inetpub\wwwroot\wss\VirtualDirectories\80
     
    1. Click Open
    2. In the Solution Explorer, right-click on the web site and choose New Folder
     
     
    1. Rename this folder to: WebServices
    2. Because you may have multiple web services, let’s add a sub folder here that is specific to our web service:
      1. Right-click on WebServices and choose New Folder
      2. Rename this folder to: NorthwindTables
     
     
    Step 2: Create the web service
     
    1. Right-click on NorthwindTables and choose Add New Item
    2. From the Visual Studio installed templates list choose Web Service
    3. In the Name box, rename this to: NorthwindTable.asmx
     
     
    1. Uncheck the option “Place code in a separate file” and click Add
     
     
    Step 3: Add the web methods
     
    NOTE: For this sample, it is assumed the SQL Server database is installed on the same Microsoft Office SharePoint Server. 
     
    1. Add the following “using” declarations at the top of your code page: 

    using
    System.Data;
    using System.Data.SqlClient;
     
    1. Add the following web method to retrieve the CustomerID values from the Customers table in the Northwind database:
     
    [WebMethod]
    public DataSet GetCustomers() {
                // Create a SQL connection to the Northwind sample database
                SqlConnection cn = new SqlConnection("Data Source=(local);Integrated Security=SSPI;Initial Catalog=Northwind");
     
                // Create data adapter object passing it the SELECT
                // statement to retrieve the customer ID values
                SqlDataAdapter da = new SqlDataAdapter("SELECT Customers.CustomerID FROM Customers Order By CustomerID", cn);
     
                // Create a dataset object to store the data
                DataSet ds = new DataSet();
     
                // Open the connection
                cn.Open();
     
                // Fill the dataset
                da.Fill(ds, "Customers");
     
                // Clean up
                cn.Close();
                cn = null;
                da = null;
                
                return ds;
                }
     
    1. Add the following web method to retrieve the associated orders for the selected customer:

    [WebMethod]
    public DataSet GetOrdersForSelectedCustomer(string strCustID) {
                // Create a SQL connection to the Northwind sample database
                SqlConnection cn = new SqlConnection("Data Source=(local);Integrated Security=SSPI;Initial Catalog=Northwind");
     
                // Create a string variable for the modified SQL statement
                string strOrdersSQL = "";
     
                // Create a string variable for the default SQL statement
                string strOrdersOrigSQL = "SELECT * FROM Orders";
     
                // Some of the customer ID values contain apostrophe's - we need
                // to replace them with two single quotation marks so that all
                // single quotation marks in the CustomerID are parsed correctly.
                strCustID = strCustID.Replace("'", "''");
     
                // Concatenate the default SQL statement with the "Where" clause
                // and add an OrderBy clause
                strOrdersSQL = strOrdersOrigSQL + " Where CustomerID Like '%" + strCustID + "%' Order By OrderID";
     
                // Create data adapter object passing it the SELECT statement
                // to retrieve the OrderID values
                SqlDataAdapter daOrders = new SqlDataAdapter(strOrdersSQL, cn);
     
                // Create a dataset object to store the data
                DataSet Ds = new DataSet();
     
                // Open the connection
                cn.Open();
     
                // Fill the DataSet
                daOrders.Fill(Ds, "Orders");
     
                // Clean up
                cn.Close();
                cn = null;
                daOrders = null;
                     
                return Ds;
    }
     
    1. Build and save the project
     
     
    Step 4: Test the web methods
     
    NOTE: The Identity account of the Application Pool for the web site where this web service is published will need to have access to the SQL Server database.
     
    1. Open a browser and navigate to: http://<server>/_layouts/WebServices/NorthwindTables/NorthwindTables.asmx (replace <server> with the name of your server)
    2. You should see the two web methods created above along with the default HelloWorld web method:
     
     
    1. Click the GetCustomers link and then click Invoke – this should return a list of the CustomerID values
    2. Click the GetOrdersForSelectedCustomer link, in the strCustID box enter: BERGS and then click Invoke – this should return a list of only those OrderID values for BERGS
     
     
    Step 5: Create the InfoPath form
     
    1. Design a new, blank, browser-compatible InfoPath Form Template
    2. Add a drop-down list box to the view and modify the name to: SelectCustomer
    3. Add another drop-down list box to the view and modify the name to: SelectOrder
     
     
     
    1. Add a new “receive data” data connection to the NorthwindTables web service for each of the web methods created above as follows:
      1. GetCustomers:
        • Enable the option “Automatically retrieve data when the form is opened”
      2. GetOrdersForSelectedCustomer:
        • Use ALFKI as the sample value for the strCustID parameter when prompted in the Data Connection Wizard
        • Uncheck the option “Automatically retrieve data when the form is opened”
    2. Set the Data source for SelectCustomer to the GetCustomers data connection and use the CustomerID field for both the Value and Display name properties
    3. Set the Data source for SelectOrder to the GetOrdersForSelectedCustomer data connection and use the OrderID field for both the Value and Display name properties
    4. Create a Rule on SelectCustomer with the following actions:
      1. Set a field’s value: Set the SelectOrder field to nothing (e.g. leave the Value blank)
      2. Set a field’s value: Set the parameter value (strCustID) for the GetOrdersForSelectedCustomer data connection to the SelectCustomer field
      3. Query the GetOrdersForSelectedCustomer data connection
     
     
    1. Save the form locally as FilteredDrop-downs_IPFS.XSN
     
     
    Step 6: Publish the form
     
    1. Publish the form to a server running InfoPath Form Services
    2. Navigate to the form library where the form was published and click the New button
    3. From SelectCustomer choose BERGS
    4. Click SelectOrder – only those orders for BERGS are displayed
    5. Select a different customer – notice the orders have also changed
     
    Scott Heim
    Support Engineer
  • Microsoft InfoPath 2010

    Add a Dynamic Map to a Contact Form using REST Web Services

    • 25 Comments

    Update: Due to a change in the Bing Maps REST Web Service, the steps outlined in this blog post no longer work. We are looking into the possibility of using a different API, and will update this post soon with details.

    Hi, Phil Newman here from the InfoPath team. In this post, I’ll explain how to use the new REST Web service data connection in InfoPath 2010 to add a dynamic map to a contacts form. The form connects to two Web services. The first is a REST Web service that returns the coordinates of a given address from Bing Maps, the second returns an image of a map for a given coordinate set. When users enter address information in the form, the map will update to display the specified address.

    Get Microsoft Silverlight

    The following steps assume that:

    1. You’ve already created your Contacts list in SharePoint and customized the form for the list in InfoPath.
    2. You have a Bing Maps key (see http://msdn.microsoft.com/en-us/library/ff428642.aspx)

    Add the Data Connections

    1. In InfoPath Designer, click “From REST Web Service” on the “Data” tab. Data Tab, From REST Web Service
    2. On the first page of the Data Connection wizard, enter the URL of the Bing Maps REST Web service that will return the GPS coordinates for the specified address. The URL must contain sample parameters that will return valid values at runtime. Otherwise the connection will not be configured. Data Connection Wizard - Web Service Details Here is my starting URL (you will need to replace YourBingMapsKey with your own Bing Maps key value) :
      http://dev.virtualearth.net/Services/v1/GeocodeService/GeocodeService.asmx/Geocode?culture=en-us&count=10&query=1%20Microsoft%20Way%20Redmond%20wa%20&landmark=&addressLine=&locality=&postalTown=&adminDistrict=&district=&postalCode=&countryRegion=&mapBounds=&currentLocation=&curLocAccuracy=&entityTypes=&rankBy=&key=YourBingMapsKey 
      Note that I’ve included a default address of “1 Microsoft Way Redmond WA” so that the Web service will return valid XML.
    3. On the next page of the Data Connection wizard, specify a name for the data connection. Since in this scenario we only want the map to be displayed when the user enters an address, clear the “Automatically retrieve data when the form is opened” check box, and click “Finish”. Data Connection Wizard - Data Connection Name
    4. Because the Bing Maps Web service is not on the SharePoint server, the data connection must be converted to a data connection (.udcx) file. Click “Data Connections” on the “Data” tab, select the data connection, and click “Convert to Connection File”. The connection file must be saved to a Data Connection Library on the SharePoint site and approved before it can be used.  (For more about data connections and UDC files, go here)Data Ribbon tab - Data Connections

    RESTSaveConnectionFile

    RESTSaveConnectionFile2

    Add a Rule to query the REST Web Service

    The next step is to create a rule to change the parameters in the REST Web Service URL based on the address values entered in the form. The Web service will then be queried using these parameters.

    1. Add a button to the form.
    2. Select the button and click “Manage Rules” on the “Home” tab.RESTManageRules

      (NOTE – the button is being used as a temporary placeholder for creating the rules. In InfoPath 2010, you can copy and paste rules between controls. We’ve built in smarts so that when you copy a rule to a different control, field references are updated. In this case we do not want the references to be updated so we will create the rules on the button and then copy and paste it on to the Address fields.)

    3. On the “Rules” task pane, click “New”, “Action” and add a “Change REST URL” rule action. 
    4. Build an expression that concatenates values in the form to create the URL RESTRuleDetails
      • In the “Insert Formula” dialog, select the existing URL  RESTInsertFormula
      • Click the “Insert Function” button and add the Concat function from the “Text” category.
      • Replace the default value for the address with parameters from the form. Since the Concat function concatenates strings, each hard coded string must be in quotes. Use the “Insert Field or Group…” button to add fields from the form to the expression.
      • Click OK in the “Insert Formula” and “Rules Details” dialogs. The underlined words in the image below are fields in the form being used as parameters in the URL. RESTInsertFormula2
      • Here is the Formula (you will need to replace YourBingMapsKey with your own Bing Maps key value) :
        concat("http://dev.virtualearth.net/Services/v1/GeocodeService/GeocodeService.asmx/Geocode?culture=en-us&count=10&query=", Address, ", ", City, ", ", State/Province, "&landmark=&addressLine=&locality=&postalTown=&adminDistrict=&district=&postalCode=&countryRegion=&mapBounds=&currentLocation=&curLocAccuracy=&entityTypes=&rankBy=&key=YourBingMapsKey") 
    5. Add a “Query for Data” rule action to query the REST Web Service with the new URL parameters.

    Add a Rule action to set the URL of the Map picture control

    To display the map of the current location in the picture control, append the latitude and longitude values returned by the Bing Maps REST Web Service to the URL for that image.

    1. Add a “Set a field’s value” rule action to set the URL of the picture control to the map of the current location.
    2. Set the value of the field to the following expression in which “Latitude” and “Longitude” are fields from the REST Web service response. The expression used to build the map image URL is as follows (you will need to replace YourBingMapsKey with your own Bing Maps key value) :
      concat("http://api.tiles.virtualearth.net/api/GetMap.ashx?ppl=24,,", Latitude, ",", Longitude, "&key= YourBingMapsKey")
    3. Add a condition to the rule so that it only executes if the Address, City and State / Province fields are not blank.
    4. Copy the rule from the button you created earlier and paste it onto the Address, City and State / Province controls.
    5. Add a rule to the picture control to hide it if the URL is blank.
    6. From the File tab, click “Quick Publish”.

    Now, open the form in the browser and fill it out. As soon as you have entered an address, the map of that location will appear in the form.

    3 important things to remember when using the REST Web Service data connection:

    1. Always start with a valid URL for your REST Web service.
    2. To change the parameters in the URL, add a “Change REST URL” rule action.
    3. To execute the connection, add a “Query for Data” rule action.

    Please leave a comment if you have any questions or feedback about this feature!

    Phil Newman

    Program Manager

  • Microsoft InfoPath 2010

    Conditional Default Values

    • 24 Comments

    Sometimes you want the default value of a field to be dependent upon a condition. However, there isn’t any direct functionality to support IF statements in the default values of fields. Substituting a rule for a default value only gets you so far, as the rule is only applied when that field that changes, not the fields that the rule depends on. Updating the field whenever any dependent field is changed would require you to copy the rule to each field.  This is not very maintainable, so below I will describe two approaches to avoiding this.

    The first approach is simple, but it has some limitations and caveats.  The second approach is more complicated, but should work in all cases. 


    Method 1: Using the union and array indexer operators

    The first approach is to use the union operator ‘|’ along with an array indexer ‘[]’ to select the proper value.  For example,

    if (BoolCondition) {
       TrueResult
    } else {
       ElseResult
    }

    becomes

    (TrueResult | ElseResult) [(BoolCondition) + 1]

    You can see that (TrueResult | ElseResult) creates a node set, while [(BoolCondition) + 1] selects which node to choose.  BoolCondition will evaluate to 0 or 1 (depending on its truth value).  Then 1 is added because the node set is 1-based, not 0-based. 

    As a simple example, say that you want to set field3 to field2 if field2 is 10 greater than field1; otherwise set field3 to field1.  On field3’s default value, the expression would be

    (../my:field1 | ../my:field2)[( ../my:field2 > ../my:field1 + 10) + 1]

     

    There are two caveats to using this approach:

    1) The node set will always be returned in document order. It does not matter what the order is in the parenthesis, as (field1 | field2) == (field2 | field1). Since you cannot change the node set ordering, you may have to modify your BoolCondition to be NOT-ed. For more information on document order, you can visit the w3.org page on XPaths.
    2) Inside of the parenthesis, you must only have nodes; you cannot have strings or any other type. So (field1 | “hello world”) will not work.


    Method 2: Using concat, substring and string-length

    To overcome these caveats, you can use the second approach here.  That is to use concat, substring and string-length.  For example, the same generic if statement from the previous approach converts to

    concat(

    substring(TrueResult, 1, (BoolCondition) * string-length(TrueResult)),

    substring(ElseResult, 1, (not(BoolCondition)) * string-length(ElseResult)))

    The key here is that BoolCondition will evaluate to 0 or 1.  Therefore, the first substring will either take no characters (if BoolCondition is false), or it will take all of the characters (if it is true) of the TrueResult.  Conversely, the second substring is evaluated with the “not” condition.  Therefore, either the TrueResult or the ElseResult will be returned in their entirety, but not both. 

    Let’s say that we want to use the same example as the first approach above,

    concat(

    substring(../my:field2, 1, (../my:field2 > ../my:field1 + 10) * string-length(../my:field2)),

    substring(../my:field1, 1, (not(../my:field2 > ../my:field1 + 10)) * string-length(../my:field1)))

    The major advantage to this approach is that you can use strings, numbers or anything else as the TrueResult and ElseResult.  For example, we could have placed “Success” and “Undefined” instead of ../my:field1 and ../my:field2. 

    That is all you need to create conditional statements in your default values! I'm attaching a sample form template that has this technique implemented (save the XSN locally before opening it). This method works on InfoPath 2003, 2007, and in browser-enabled form templates. 

    Thanks to Alexei Levenkov and Gary Hsu for their assistance on this article. 

    Nicholas Lovell
    Software Design Engineer

  • Microsoft InfoPath 2010

    InfoPath File Attachment Control

    • 21 Comments

    File Attachment Control

    Applies to: Microsoft Office InfoPath 2003 SP1

    Microsoft Office InfoPath 2003 SP1 introduces a number of new controls.  One of these new controls, the file attachment control, enables you to insert files which will be encoded and saved with the form. This control opens up a number of new scenarios not easily possible before SP1. 

    For example, let’s say that you have created a form that will be used by your sales people in the field. Typically, your sales people may track large amount of sales data in an Excel spreadsheet which includes fancy charts and pivot tables.  When these sales people report their quarterly earnings, you would like them to fill out an InfoPath form so that you can gather data such as total sales per region.  However, since the sales people have already gathered all the detailed sales data in an Excel spreadsheet, you don’t want them to have to reenter the data into the InfoPath form.  Instead, your sales people click on a file attachment control and attach the spreadsheet containing their sales data.  Later, when you are reviewing the data in the InfoPath form, you can double-click the spreadsheet file and open it in Excel in order to view the detailed sales data.

    Adding a file attachment control to a form is easy.  Just follow these four basic steps:

    1. Start InfoPath and design a new blank form or design an existing form.
    2. Open the Controls task pane by clicking on the Controls link in the Design Tasks pane.
    3. Look for the File Attachment control under the File and Picture category of the Controls task pane.
    4. Insert the file attachment control by clicking on it or dragging and dropping it into the view.

    Now, when you preview the form or fill out a form based on this form template, users can attach files to your form.  Also, if you open a form that has existing file attachments, you can double-click on the control to open it.  When opening files that are already attached, by default, the application that is associated with that file’s extension on your system is opened in order to view the file.

    Security

    For security reasons, not all types of files can be attached to a form.  The last thing you want is for somebody to attach a malicious executable file that formats your hard drive.  For this reason, InfoPath blocks certain file types from being attached (e.g., .exe, .com, .bat, etc.).  To determine the types of files that are considered unsafe, InfoPath follows a similar model as Outlook which is documented in http://support.microsoft.com/default.aspx?scid=kb;EN-US;290497.

    In addition to the list of file types blocked by default, you can further restrict the types of files you want users to attach to your form.  To do so, perform the following:

    1. Follow the steps above to insert a file attachment control into the view.
    2. Double-click on the file attachment control that you just inserted into your form in order to open the properties dialog for the control.
    3. On the Data tab of the properties dialog, check “Allow the user to attach only the following file types” option.
    4. In the textbox below this option, enter the extension or extensions of the file types that you want your users to be allowed to attach to the form.  Use semi-colons to separate multiple file extensions (e.g., doc; ppt; xls).

    Technical Details

    Upon attaching a file, InfoPath first builds a header structure which includes information about the file being attached. The structure consists of the following:

    ·         BYTE[4]: Signature (based on the signature for PNG):

    (decimal)                       199       73         70         65
    (hexadecimal)                C7        49         46         41 
    (ASCII C notation)          \307      I           F          A 

    The first byte is chosen as a non-ASCII value to reduce the probability that a text file may be misrecognized as a file attachment.  The rest identifies the file as an InfoPath File Attachment. 

    ·         DWORD: Size of the header

    ·         DWORD: IP Version

    ·         DWORD: dwReserved

    ·         DWORD: File size

    ·         DWORD: Size of file name buffer

    ·         File name buffer: variable size

    After building the header structure described above, the header and file data are concatenated and base64 encoded.  This base64 data is then stored with the XML data in the form.  (More information about base64 encoding can be found here: http://www.w3.org/Protocols/rfc1341/5_Content-Transfer-Encoding.html.) 

    If you wish to write code to work with InfoPath file attachments, the .NET framework provides a Convert class that includes methods to encode and decode base64 data (e.g., Convert.FromBase64String). These methods can be used to decode existing InfoPath file attachment data or to encode a file for storing in an InfoPath form.

    When a file attachment control is inserted into an InfoPath form, the following processing instruction is inserted into the XML template for the form:

    <?mso-infoPath-file-attachment-present?>

    This processing-instruction is added as a convenience for InfoPath but is not meant to be a security feature. If this processing-instruction is removed, when users fill out the form, all file attachment controls will be disabled.

  • Microsoft InfoPath 2010

    Introducing the InfoPath SP1 Master/Detail Control

    • 21 Comments

    Applies To: Microsoft Office InfoPath 2003 SP-1 Preview

    InfoPath SP-1 introduces a number of exciting new built-in controls.  One of which is the Master/Detail control.  After InfoPath 2003 was released, one of the most common questions on the InfoPath newsgroups was how to implement a Master/Detail type of control in InfoPath.  Although this was possible in InfoPath 2003 prior to SP-1, doing so was not easy or straightforward.  For this reason, InfoPath 2003 SP-1 now includes built-in support for the Master/Detail control.

    The Master/Detail control allows you to designate one control as a master that drives the data in another control which is called the detail.  When the user selects an item in the master, the corresponding data in the detail is displayed.

    When designing a form template in InfoPath design mode, inserting a Master/Detail control into your form is easy. There are actually two ways to do so.  The first way is to use the Master/Detail control in the Controls toolbox.  Inserting the Master/Detail control from the Controls toolbox actually inserts two controls – a Repeating Table that is designated as the master and a Repeating Section that is designated as the detail.  When you insert the Master/Detail control this way, as long as the “Automatically create data source” checkbox in the Control toolbox is checked, a simple data structure is created in the data source. This structure consists of a group node containing one repeating group node that, in turn, contains four child fields. The master and detail are both bound to the inner repeating group node. In this case, the master and detail are said to be linked by position in the tree.  This basically means that if you select the third item in the master control, for example, the data for the third item is displayed in the detail control. This enables you, for example, to build a form that contains basic customer information, such as customer name and SSN, in the master and more detailed information about that customer such as address and phone number, in the detail.

    The second way to create a Master/Detail relationship is by manually specifying which control is the master and which is the detail. Although this is a bit more difficult than choosing the Master/Detail control from the Controls toolbox it does give you more control over how the master is linked to the detail. (As mentioned earlier, one way of linking a master control to a detail control is by position. The second way to link a master to a detail is by key field. This type of linking allows you to specify a primary key/foreign key type of relationship where the value of the primary key in the master determines which detail data is displayed. This type of linking is only available when creating a Master/Detail relationship manually.)

    To create a Master/Detail relationship manually, perform the following steps:

    1. Insert a Repeating Table control. This control will act as the master. (Only Repeating Tables can act as master controls.)
    2. Open the Repeating Table Properties dialog either by double-clicking on the Repeating Table tab at the bottom of the control or by selecting the Repeating Table and then clicking on the Format | View Properties menu item.
    3. Click on the Master/Detail tab
    4. Click the “Set as master” option button and then type a name into the “Master ID” text box. This ID will be used to specify the master to link to when designating another control as the detail.
    5. Click OK to close the dialog and commit the changes to the Repeating Table properties. (At this point, you will notice that the tab at the bottom of the Repeating Table now contains the text “(master)” which designates that this control is now a master control.)
    6. Now, insert another Repeating Table or a Repeating Section control. This control will act as the detail control. (If you want to link the master to the detail by position, it is better to insert a Repeating Table or Repeating Section control that is bound to the Repeating Table you created in step 1. Link by position is the default behavior when inserting the Master/Detail from the Controls toolbox as mentioned earlier.)  If you insert a new Repeating Section control, you will want to add controls inside the Repeating Section in order to display the detail data.
    7. Open the properties dialog for the Repeating Table or Repeating Section as in step 2 above.
    8. Click on the Master/Detail tab
    9. Click the “Set as detail” option button.
    10. From the “Link to Master ID” dropdown, choose the ID that you created in step 4 above.
    11. Now, you have to specify how the master and detail are linked. By default, the master and detail are linked by position. Since we already talked about this type of linking above, click the “By key field” option button instead.
    12. In order for this type of Master/Detail relationship to work, you need to specify which field in the data source is the master key and which field is the detail key.
      1. Click on the data source button to the right of the “Key field (master)” edit box and choose the field from the master that should be used as the master key.
      2. Then, click on the data source button to the right of the “Key field (detail)” edit box and choose the field from the detail that should be used as the detail key.
    13. Click OK to close the properties dialog and commit the changes. (At this point, you will notice that the tab at the bottom of the Repeating Table or Repeating Section now contains the text “(detail)” which designates that this control is now a detail control.)

    Now, when you use your form, you will notice that when you select an item in the master, only those detail items whose detail key matches the master key of the currently selected item in the master control will be displayed. 

    Obviously, if there is no data, no details will be displayed.  InfoPath provides a nice way to deal with this situation. When walking through the steps to manually create as Master/Detail relationship above, you may have noticed the option “Copy key field from selected master when inserting detail” which is checked by default.  This option designates that when inserting a new detail item, the value of the master key of the item that is currently selected in the master control will be automatically copied to the detail key in the new detail item. This is quite convenient when creating Master/Detail data from scratch.

    As you can see, creating a Master/Detail relationship in InfoPath 2003 SP-1 is very easy and is just one of the many new features that were added in direct response to customer feedback.

  • Microsoft InfoPath 2010

    Compatibility between InfoPath 2003, 2007, and Forms Server

    • 20 Comments
    Ask and ye shall receive. Here's a short summary of how to think about compatibility when designing form templates in InfoPath 2007.
     
    1. InfoPath 2003 forms will work as-is in 2007
    Your existing forms should work. Period. If you find something that doesn't work, please leave a comment so we can get that bug fixed.
     
    2. InfoPath 2007 can save as InfoPath 2003 forms
    Most features actually work in 2003, we just made 2007 the default to be forward-looking. If you plan to design all your forms to be compatible with InfoPath 2003, you can change the default in the Options dialog off the Tools menu:
     
     
    You can also save individual forms as the file type 2003:
     
     
    When you save a file for InfoPath 2003, we automatically check this box in Form Options:
     
     
    So that the design checker will show you compatibility issues:
     
     
    You can get more info on each issue by clicking it, and then fix it appropriately. Forms with "Messages" will successfully save for 2003, but forms with "Errors" cannot be saved for 2003 until all the errors have been fixed.
     
    3. InfoPath 2003 forms can also work on the Forms Server
    If you have the InfoPath 2003 client rolled out to your desktops, and also have the Forms Server, then you can create forms that will open in the browser for people without any copy of InfoPath, but open in the client for those with InfoPath 2003 (and 2007, see point 1 above).
     
    First, follow the steps above to save your form to be compatible with InfoPath 2003. Then check this box in Form Options to make the form browser-compatible:
     
     
    Now you can fix any remaining issues shown by the design checker, and publish the form to Forms Server the same as any other browser-enabled form.
     
    Hope that helps,
    ned
  • Microsoft InfoPath 2010

    Inserting line breaks into text using Rules

    • 19 Comments

    Q: How do I insert line breaks into a multi-line text box using rules?

    First off, let’s introduce the concept of a multi-line text box properly. This functionality was added in InfoPath 2003 SP1. To enable it, insert a Text Box control, then on the Display tab, check “Paragraph breaks”. I usually also set the scrolling property to “Show scrollbars when necessary” and turn on “wrap text” which maps to the usual behavior for a multi-line text box. I also usually make the control bigger.

    Without the “Paragraph breaks” property set, line breaks (CR, LF or CRLF) in the XML data are treated as any other whitespace and show up in a text box as spaces. The Enter key is ignored, and breaks are stripped on paste. With this property set the breaks are preserved and show in the control, and can be typed and pasted.

    That’s good enough for round-tripping pre-existing breaks in the XML data and allowing user editing. And since you can party on the DOM as much as you want, inserting them via code is easy too – use whatever the escaping mechanism your language of choice provides – for example, in JScript you might use: oNode.text = "abc\r\ndef"

    How about rules? One of the rule actions available is to set a field’s value to the result of an expression. Behind the scenes, when the rule fires the expression is evaluated to return a string, and then the string is injected into the XML DOM as the node’s text. Specifying expressions like concat("abc", "&#xA;", "def") will result in a literal “&”, “#”, “x”, “A” and “;” appearing in the XML text. &-encoding is part of the file format, not of the DOM! The expression concat("abc", "\n", "def") and other variants don’t work either – there’s no escaping mechanism in the evaluation used here.

    So you need to figuratively copy/paste the line break from another source. Start off by literally doing a copy/paste of the following text into Notepad:

    <?xml version="1.0" encoding="UTF-8"?>
    <characters
        cr="&#xD;"
        lf="&#xA;"
        crlf="&#xD;&#xA;"
    />

    Save this as a file called “characters.xml”. Then in InfoPath go to Tools | Data Connections and click Add. Select Receive data, then XML Document. Browse to characters.xml then complete the wizard. When it asks “The selected file is not part of the form...add this file...?” click Yes. At this point we’ve just added a resource file to the template that gets loaded into a declaratively-accessible DOM - no code required.

    Almost there - now let’s use it!

    Add a Button control, open up the properties and click Rules. Add a Rule, and add an Action of the type “Set a field’s value”. For the field pick the text box’s field (e.g. field1). For the new value, use the formula builder and build the following expression:

    concat(field1, @crlf, "Hello, world!")

    The underlines indicate that this is a simplified version of the expression that conceals the full XPaths. Instead of typing it's easier to pick the fields using the “Insert Field or Group” button. Pick field1 from the main data source and pick @crlf from the “characters (Secondary)” data source (using the drop-down at the top of the dialog). Behind the scenes (as you can tell by clicking the “Edit XPath” button) this builds up the following expression:

    concat(my:field1, xdXDocument:GetDOM("characters")/characters/@crlf, "Hello, world!")

    Once you're done, click Preview, and try clicking the button a few times.

    As a final note, InfoPath is agnostic about the whole CR vs. LF vs. CRLF debate. Any of the three is equally treated as a line break.

     

  • Microsoft InfoPath 2010

    Using Multiple Views in Customized List Forms

    • 19 Comments

    Hi, my name is Laura Harrington, and I’m a program manager on the InfoPath team. In this short video demo, I will show how you can optimize the form filling experience for different tasks and users by creating multiple custom views in your customized SharePoint list forms.

    Get Microsoft Silverlight
Page 1 of 12 (298 items) 12345»