Category Archives: InfoPath

How to view a version of an InfoPath form

Today I had a situation where I needed to see what a person originally submitted, i.e., the initial version of an InfoPath form with version history enabled. While you can revert to prior versions easily via the SharePoint UI, I haven’t figured out an out-of-the-box way to view a prior version of an InfoPath form. However, after tinkering with the URL gotten via the Modified column in the Version History dialog, I saw the part of the URL that gives me all the XML data. The URL part looks like this:

XmlLocation=http://server/site/subsite/_vti_history/<VersionNumber>/FormLibName/FileName.xml

If you copy and paste the URL, i.e., http://server/site/subsite/_vti_history/VersionNumber/FormLibName/FileName.xml, into a browser, you should be able to either render it as XML (if you have an extension or add-in that does that), or you can download it and open it in your preferred text editor. I’ve tried without success to open the prior version of the form in the browser. I keep getting an error, and other people seem to get errors too.

Getting the current list item with the SharePoint object model

You can do tons of stuff with out-of-the-box InfoPath rules and data connections. The problem with these no-code techniques is that they are difficult to debug. Using code-behind is great for stepping through the code in a debugging session, and also there are some things are just quicker to do in code. For example, say you want to get some information that is usually stored with the list item, such as the title field. You’ll need that if you are using InfoPath data connection wizard to submit or update the corresponding list item. The easiest way to get the current item (the InfoPath form) is through SPContext.Current.Item. Note that you should not explicitly dispose of SPContext objects in your code.

Simple solution to filtering InfoPath dropdown menu items

If you want to display only certain lookup items in a dropdown menu in InfoPath (without code or rules), all you have to do is apply item-level permissions, for the appropriate users/groups, to the SharePoint list items that are referenced by dropdown’s SharePoint list data connection. The dropdown menu items are filtered automatically based on the current user having at least Read permission on each SharePoint list item. Here is a corresponding forum post.

Lessons learned today with InfoPath

When you upload or upgrade an InfoPath form template via Central Admin, it sometimes can give you unhelpful error messages, such as “There was an unknown error,” or something like that. I had included in my code-behind invocations of utility methods that were not published yet. I couldn’t find anything in the SharePoint logs. And my form’s design checker was only giving me warnings about some unknown XSL element. So after many trips to TFS to try prior versions to see what broke, I remembered what I did today that was new: the utility methods. So SharePoint was really trying to tell me, in its weird way, that I was calling an unknown method. I’m sure there is a way to find or trap that error, but my lesson learned was to think about everything you did that day that could have caused an error.

Lesson #2 had to do with sorting a repeating table. My scenario was that I had a SharePoint list, and I wanted two of its columns, the title and the description, to appear in a repeating table, and then use a checkbox field in InfoPath to do multiple selections. A out-of-the-box multi-select list box control in InfoPath 2010 usually works for this kind of scenario, but since I needed title and description fields displayed, I needed to roll my own. My lesson learned was that the sorting code is case sensitive. I was trying lots of other sorting routines, when my problem was just that the case was not perfect. Here’s my code that I used for sorting (not generalized).

private void PopulateRepeatingGroup(Connections dataConn, string dsNodeXPath, string groupXPath, string selectedOptionCodeValue, string selectedFieldXPath, string formOptionCodeXPath, string secondaryXmlOptionCodeXPath, string formOptionNameXPath, string secondaryXmlOptionNameXPath, string formOptionDescriptionXPath, string secondaryXmlOptionDescriptionXPath)
{
    XPathNavigator xnav = MainDataSource.CreateNavigator();
    DataConnections[dataConn.ToString()].Execute();
    XPathNavigator xnavServiceReferences = DataSources[dataConn.ToString()].CreateNavigator();
    XPathExpression xe = xnavServiceReferences.Compile(dsNodeXPath);
    xe.SetContext(NamespaceManager);
    xe.AddSort("*[local-name()='displayName']", XmlSortOrder.Descending, XmlCaseOrder.None, null, XmlDataType.Text);
    XPathNodeIterator xi = xnavServiceReferences.Select(xe);
    while (xi.MoveNext())
        AddNodeToNodeList(xi.Current, groupXPath, selectedOptionCodeValue, selectedFieldXPath, formOptionCodeXPath, secondaryXmlOptionCodeXPath, formOptionNameXPath, secondaryXmlOptionNameXPath, formOptionDescriptionXPath, secondaryXmlOptionDescriptionXPath);

    //Delete the last row of InfoPath Repeating table programmatically
    xnav.SelectSingleNode(groupXPath + "[" + (xi.Count + 1) + "]", NamespaceManager).DeleteSelf();
}

My last lesson for today was to remember to remove item event receivers, and later add them back, when doing anything that triggers an update of the item, for which you do not want the event receiver to run. My situation had to do with adding permissions in the InfoPath code-behind. When you update an item’s permissions, it will trigger an item update. This code was run infrequently, and was not well-tested, until now. So, I programmatically added, and subsequently removed, the specific ItemUpdated event receiver from the list, thereby disallowing an item update event to be triggered.

InfoPath 2010 validation rules: must use ScreenTip

One cool thing about InfoPath is that you have a nice GUI to enter field validation rules, and displaying screentips and dialogs are out of the box. Problem is, the ScreenTip field is required when entering validation rules, and they sort of get in the way of the user. Hovering over the field with an error produces an unsightly message above the field, and users not used to InfoPath might cry foul.

There is simple “Cannot be blank” validation, in which you just check a box on the field properties dialog. This will produce a ScreenTip that, wait for it… says “Cannot be blank”. This is fine for the most trivial validation scenarios, because that validation rule will always be triggered. So, simple “Cannot be blank” validation rules are only good on fields that must be valid at all times. Many fields will require conditional validation, which is where the traditional validation (by rules or events) comes into play, which I’m talking about below.

In the InfoPath 2007 designer, you must put something into the ScreenTip field, or you can’t save the validation rule. The trick to bypass this requirement is to put a dummy string, like “$$$$” in the ScreenTip field, and then, outside the InfoPath designer, do a “Replace All” on the manifest.xsf to substitute an empty string for “$$$$”. This ensures the ScreenTip is not rendered (at least in the browser), which is nice if you don’t want it rendered.

In InfoPath 2010, however, the designer will let you save and publish with a blank ScreenTip field. I thought that was great, because it would save me the “Replace All” step; but interestingly, InfoPath 2010 actually deletes some validation rules with blank ScreenTip fields. It does this when saving and publishing.

So, be sure to actually fill in something on the ScreenTip fields. If you don’t have anything substantive to put in the ScreenTip field, you can put a blank space to reduce the ScreenTip down to a small, innocuous box when mousing over the field. But you need to put something, or InfoPath 2010 will delete your validation rule.

How to debug an InfoPath browser form

Besides the debugging capability of the InfoPath client, you can debug an InfoPath form through Visual Studio just as you would debug an ASP.NET page.  Check out this article for the details.

One build on the article’s debugging strategy is to add the following code to the FormEvents.Loading method in your code-behind.

        public void FormEvents_Loading(object sender, LoadingEventArgs e)
        {
            string debug;
            e.InputParameters.TryGetValue("Debug", out debug);
            if (!string.IsNullOrEmpty(debug))
            {
                int debugInt;
                int.TryParse(debug, out debugInt);
                if (debugInt == 1)
                {
                    Debugger.Launch();
                    Debugger.Break();
                }
            }

That way you can append Debug=1 to the URL when you want to debug.

How to display to the user that the text value was deleted

When you’re writing a form (any form, but InfoPath is what this entry deals with specifically) that has to tell the user/approver that a value has been changed, something that can be overlooked is the case when a value is deleted.  I had conditionally formatted expression boxes to be bold-formatted when the old value doesn’t equal the new value.  That’s fine, but when the value is blank, that solution yields a bold-formatted empty string which is, of course, invisible.  To work around this, I added another expression box that only displays a string saying something like, “value changed to blank.”  Then I added conditional formatting to hide that expression box with a formula like this:  Hide this if X was not modified or X is not blank.  That will hide the “value changed to blank” box when the original value wasn’t changed or the change was to a non-blank value.  It will show the box when X was modified and X is now blank.  You don’t have to implement this on all fields, because some fields will have validation that disallows blank values.  Also, some fields’ data types, such as boolean, do not allow blank values.

How to prevent InfoPath infinite loops on event handlers

I created an OnChanged event for an InfoPath field which raised this error:

System.InvalidOperationException
An error occurred in the form’s rules or code. The number of rule actions or the number of calls to the OnAfterChange event for a single update in the data exceeded the maximum limit.

The rules or code may be causing an infinite loop. To prevent this, ensure that the rule action or event handler does not update the data which causes the same rule action or event handler to execute.

First of all, remember to put try / catch blocks around all exposed code.  Don’t wait until it shows up in the Event Log.  E-mail each error to yourself if possible.

This code below is an example will raise that error.

public void InternalStartup()
{
    EventManager.XmlEvents["/my:myFields/my:field1"].Changed += new XmlChangedEventHandler(field1_Changed);
}

public void field1_Changed(object sender, XmlEventArgs e)
{
    e.Site.SetValue(e.NewValue + "a");
}
 

One way to avoid this error is just don’t do it: change the value of this field during submit or some other time.

Another way is to check a variable to see whether the update is referring to the first time or a recursive call.

public void field1_Changed(object sender, XmlEventArgs e)
{
    string memberVar = FormState["_memberVariable"] as string;
    // if the FormState variable has the field cached, exit to prevent recursion
    if (!string.IsNullOrEmpty(memberVar) && memberVar == e.OldValue)
        return;

    FormState["_memberVariable"] = e.NewValue;
    e.Site.SetValue(e.NewValue + "a");
}

Speaking of event bubbling, check out Greg Collins’ article from 2004.  I haven’t used this functionality yet: if you put an OnAfterChange event handler on a group node, it will handle event changes for all nodes and attributes below it.

How to update a rich text field programmatically in InfoPath

There are several gotchas when you update InfoPath fields programmatically.  If you just use rules from within the Designer, it handles these problems for you.  But 90% of the time I’m mucking around in InfoPath code, so this lesson needs to be repeated.  If you have a rich text field, make sure to use the XPathNavigator.InnerXml property for getting and setting the XML or XHTML value.  When I use the XPathNavigator.Value property on a rich text field, I consistently get an empty string back.  There’s probably an object-oriented way to test for rich-text fields, but for now, I manually identify them.  Using custom methods, you can genericize these updates.

Don’t forget to delete the nil attributes when setting the types of fields below with non-empty values.  If you aren’t sure whether a field is nillable, check your form template’s template.xml file.  Here’s the way to go about this programmatically.

  • Whole Number (integer)
  • Decimal (double)
  • Date (date)
  • Time (time)
  • Date and Time (dateTime)
  • Rich Text (XHTML)
  • True/False (Boolean)
  • Hyperlink (anyURI)
  • Picture of File Attachment (base64)

Schema validation found non-data type errors.

Every once in a while, I’ll get this error. It’s because I was trying to set the value of a Date field that was blank. Check out the MSDN article on this, which demonstrates how to delete the nil value before setting the value on certain data types.

Follow

Get every new post delivered to your Inbox.