Microsoft InfoPath 2010
The official blog of the Microsoft InfoPath team

July, 2006

  • Microsoft InfoPath 2010

    Don't settle for just one: Adding multiple default rows

    • 10 Comments
    Since I realize not everyone has installed the Beta yet (you can do it!), I figure it's time for a trick everyone can play with, even those still using InfoPath 2003.
     
    Starting with more than one row in a repeating table
    You may want to do this if you have a form where you know everyone's going to fill out at least five rows, or maybe some people will even print our your form before typing in their answers (I never!). You might even want to have five rows exactly, and then disable adding or deleting rows (in Repeating Table properties), but still use a repeating table to get the data structure you want.
     
    Regardless of your scenario, here's how to do it:
    1. Open the form in design mode
    2. Click Default Values on the Tools menu
    3. In the data source, select the group that's bound to the row of the repeating table
    4. Click the down arrow next to the group name
    5. Select "Add another row below"
     
     
    You can even specify different values for the columns of each row using the bottom of that dialog. And of course this works for any repeating item in your data source, not just those bound to repeating tables.
     
    Keyboard trick!
    Save yourself a few clicks by typing the "Insert" key instead of using the menu. Each time you type "insert" it will add another row. Those two clicks per row can really add up when you have a lot of rows! If you type it a few too many times, you can also use the "Delete" key to remove the offending rows. 
     
    Got your own tricks to share?
    As usual, if you've got your own tips in this area, or a cool reason to use this trick, please leave us a comment for the team to see and the community to gain.
     
    Enjoy,
    ned
  • Microsoft InfoPath 2010

    Introducing the Multi-Select List Box

    • 8 Comments
    InfoPath 2007 introduces a new control, the multi-select list box, for cases when you want to allow users to select one or more items from the list of options. This list of options may be static, or may come from a data source. For example, you may use a multi-select list box to let the user pick the cities affected by the marketing campaign:
     
    You may also allow users to specify items not on the list by going to Multi-Select List Box Properties, and setting the option to allow users to enter custom values:
     
    Data source
    Multi-select list box stores data in a repeating field. Every time a user checks an option, a new instance of the repeating field is added; every time an option is unchecked, a field is deleted. This is just like the Bulleted List control.
     
    Let's analyze the data source at design time, and what goes into the XML when the form is filled out:
     
    Form Design
    Form Filling
    Data Source Pane
    User Input
    Persisted XML
    <my:campaign>
         <my:city>Chicago</my:city>
         <my:city>New York</my:city>
         <my:city>Boston</my:city>
    </my:campaign>
      
    Default Values
    To specify which (if any) items should be checked in the multi-select list box by default, click Default Values on the Tools menu. Using the marketing campaign example, if you don't want any option to be selected by default, uncheck the only "city" item:
     
     
    When you do this, you may see a design-time message that the "Control is bound to a missing field or group". You can safely ignore this message in this case since the point is to not have any checked by default.
     
    If, instead, you want several options to be checked by default, right-click on the city item, then click "Add another city below", and specify default values for both cities:
     
     
    Compatibility
    Multi-select list boxes are supported only in InfoPath 2007 client.
     
    - Alex Weinstein
    Program Manager
  • Microsoft InfoPath 2010

    Advanced server-side authentication for data connections, part 3

    • 7 Comments
    This is the final segment of my three part series. In the first part of this series I introduced the concepts involved in three tier authentication. Then I covered single sign-on with some code. Now we'll go one step further…
     
    Authorization using the Web service proxy
     
    InfoPath Forms Services includes a Web service proxy which can forward SOAP requests to a Web service to enable authorization for a data query.  The premise is simple – the proxy runs under an account that is trusted by the Web service.   The Web service authenticates the trusted account.  In addition, the proxy sends the identity of the calling user in the SOAP header using a WS-Security UsernameToken.  The Web service can then use the provided identity to determine what data to return from the query.
    Setting up a connection to use the proxy is straightforward.  First of all, the connection has to use settings from a UDC file on the server.   The UseFormsServiceProxy attribute on the ServiceUrl element in the UDC file determines whether InfoPath and Forms Services will forward the Web service request using the proxy:
     
    <udc:ServiceUrl UseFormsServiceProxy="true">
      http://myserver/proxydemo/service.asmx
    </udc:ServiceUrl>
     
    Everything else on this end is automatic.  It's a little more interesting on the Web service end.

    It's tempting to consider using the WSE 2.0 library to consume the UsernameToken from the Web service request.  WSE 2.0 has methods to automatically consume WS-Security headers.  However, the default behavior of WSE 2.0 is to attempt to logon using the credentials in the UsernameToken.  It is possible to override the default behavior by specifying an alternate UsernameTokenHandler.  However, there is a more straightforward approach.
    First, declare an array of SoapUnknownHeader at class scope in your service:
     
    public SoapUnknownHeader[] unknownHeaders;
     
    Then declare a SoapHeader attribute for the web method:
     
    [WebMethod]
    [SoapHeader("unknownHeaders")]
    public ExpenseInfo[] GetMyExpenses()
     
    In your web method, look for the UserName element in the header array, which is returned as an XML Document.
     
    if (null != unknownHeaders && unknownHeaders.Length > 0)
    {
         // look for a userNameToken and return the username if present
         try
         {
              strUserName = unknownHeaders[0].Element.CreateNavigator().SelectSingleNode("//*[local-name(.)='Username']").Value;
         }
         catch (Exception)
         {
         }
    }
     
    In the example, I'm searching for a Username element anywhere in the headers.  To be more precise, the UserName is within a UsernameToken element, which is in turn under a Security header in the WS-Security namespace.  The entire SOAP header sent by the proxy looks like this:
     
    <SOAP-ENV:Header.xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
      <wsse:Security.xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis/security-secext-1.0.xsd">
        <wsse:UsernameToken>
          <wsse:Username>DOMAIN\username</wsse:Username>
        </wsse:UsernameToken>
      </wsse:Security>
    </SOAP-ENV:Header>
     
    I've put the code to get the username within a utility function called GetUserName.  In the function, I look first for the usernametoken.  If this is not present, I get the current Windows user.  In either case, I strip off the domain portion of the identifier and return the unadorned username.
     
    private string GetUserName(SoapUnknownHeader[] unknownHeaders)
    {
      bool fUserFound = false;
      string strUserName = string.Empty;
      if (null != unknownHeaders && unknownHeaders.Length > 0)
      {
      // look for a userNameToken and return the username if present
        try
        {
          strUserName = unknownHeaders[0].Element.CreateNavigator().SelectSingleNode("//*[local-name(.)='Username']").Value;
        }
        catch (Exception)
        {
        }
        if (string.Empty != strUserName)
        {
          fUserFound = true;
        }
      }
      if (!fUserFound)
      {
        // return the current Windows identity
        strUserName = WindowsIdentity.GetCurrent().Name;
      }
      // trim off the domain string if present
      int nDomainStringIndex = strUserName.IndexOf('\\');
      if (nDomainStringIndex > 0)
      {
        strUserName = strUserName.Substring(nDomainStringIndex + 1);
      }
      return strUserName;
    }
     
    In order to use the identity to retrieve data, I use it as part of the query against my database.  Here's the entire Webmethod. The code assumes that you have an Expense database with a table called Expenses, and that one column of the table, called Employee, contains the Windows username of the employee who filed the expense.
     
    [WebMethod]
    [SoapHeader("unknownHeaders")]
    public ExpenseInfo[] GetMyExpenses()
    {
      ExpenseInfo[] oReturn = null;
      DataSet oDS = new DataSet();
      string strQuery = string.Format("SELECT ExpenseID, Description, Date, Amount FROM Expenses WHERE Employee = '{0}'", GetUserName(unknownHeaders));
      try
      {
        m_Connection.Open();
        m_Adapter = new SqlDataAdapter(strQuery, m_Connection);
        m_Adapter.Fill(oDS, "Expenses");
        int cRows = oDS.Tables["Expenses"].Rows.Count;
        oReturn = new ExpenseInfo[cRows];
        for (int nRowIterator = 0; nRowIterator < cRows; nRowIterator++)
        {
          oRow = oDS.Tables["Expenses"].Rows[nRowIterator];
          oReturn[nRowIterator] = new ExpenseInfo();
          oReturn[nRowIterator].Amount = oRow["Amount"].ToString();
          oReturn[nRowIterator].ExpenseID = oRow["ExpenseID"].ToString();
          oReturn[nRowIterator].Date = oRow["Date"].ToString();
          oReturn[nRowIterator].Description = oRow["Description"].ToString();
        }
      }
      catch (Exception ex)
      {
      }
      if (m_Connection.State != ConnectionState.Closed)
      {
        m_Connection.Close();
      }
      return oReturn;
    }
     
    - Nick
    Program Manager
     
  • Microsoft InfoPath 2010

    Multi-Select List Box: Requiring at least one entry

    • 2 Comments
    Yesterday I introduced the Multi-Select List Box and talked about how its data source is somewhat special: it binds to a repeating list of fields instead of a single field like the normal List Box does.
     
    When you need to ensure that at least one item is selected in the multi-select list box, you may be tempted to go to Muti-Select Listbox Properties to check the "cannot be blank" property; however, this property will not be available for multi-select list boxes because of their binding. Since a multi-select list box binds to a repeating field, what you really need is something that means "occurs at least once". Here's how…
     
    Visuals - Showing the red asterisk (*)
    1. Insert a multi-select list box and remove its border.
    2. Create a two-column layout table; place the multi-select list box into the first column of that table.
    3. Place an expression box into the second column of the layout table. Use static text * (asterisk) as the contents of the expression box and set its font color to red.
    4. Set up conditional formatting on the expression box:
          if count of elements in the repeating field is greater than 1, hide this control
    5. Set up a visible outside border on the layout table.
     
    The steps provided above will provide a visual indication to the user that the field is required - a red asterisk will be shown whenever the multi-select list box doesn't have any option checked. After you're done, you should see results similar to the following:
     
    Form Design
    Form Filling
     
    Preventing submit
    We still need to make sure that our users can't submit a form with this error - since nothing we've done above prevents form submission. This can be achieved in several ways:
     
    • Option 1: Use rules for form submission
    As the first step of submission, check if count of elements in the repeating field is less than 1. In that case, show an error message and stop processing all rules, essentially preventing form submission.
    • Option 2: Add data validation to another field
    if count of elements in the repeating field is less than 1. This will cause InfoPath to add an error to its Errors Collection behind the scenes if the condition is not met, and your users will not be able to submit the form.
    • Option 3: Write code for the Submit action
    In code you can check the condition and add elements to the Errors Collection as necessary.
     
    - Alex Weinstein
    Program Manager
  • Microsoft InfoPath 2010

    More than one way to write code: Visual Studio and InfoPath

    • 3 Comments
    If you need to write some Visual Basic or C# code behind your form, or maybe just some script, there are a few different tools you can use depending on which versions of InfoPath and Visual Studio you have.
     
    Here's a quick table summarizing it all:
     
     
    Note that both Microsoft Script Editor (MSE) and Visual Studio Tools for Applications (VSTA) come with InfoPath 2007 Beta, so you can open them from the Tools | Programming menu. If you don't see the one you want, change the language in Tools | Form Options. If it gives you an error that it's not installed, here's how to install them:
     
    1. If you are going to install VSTA, make sure you have the pre-requisites first:
    2. Go to Start > Control Panel > Add or Remove Programs
    3. Select your Office installation and click Change
    4. In the Office Setup wizard select to add features
    5. Find Microsoft Script Editor (under Office Tools) and/or Visual Studio Tools for Applications (under InfoPath > .NET Programmability) and select Run from my computer
    6. Finish the wizard
     
    Happy code writing!
    - Ned
  • Microsoft InfoPath 2010

    Andrew May knows XML Forms on SharePoint

    • 1 Comments
    This is a shout out to Andrew May, who's posted some great content on SharePoint as it relates to InfoPath and XML more generally.
     
    His most recent post covers the new Form content type that InfoPath uses for its Content Types integration. He's also got a great 5-part series on how the SharePoint XML parser works that InfoPath uses for our property promotion feature. He's even created a poster about how SharePoint parsers work, which you can download, print out, and hang in your bedroom, er, office.
     
    Another post covers the InfoPath integration with Document Information Panels and Workflows, which shows how important InfoPath dev skills are to the entire Office stack.
     
    On a completely unrelated note, the recent heat wave seems to have made it to Redmond, where we're in the 90's today. Yowsers!
     
    - Ned
    Program Manager
  • Microsoft InfoPath 2010

    New Article about the New Developer Features

    • 1 Comments
    Hi all,
     
    I wanted to let you know about a new MSDN article that has just recently been published which outlines the new developer features of InfoPath 2007. Feel free to post any questions or comments you have about the article.
     
    Thanks,
    Scott
  • Microsoft InfoPath 2010

    Got suggestions?

    • 8 Comments
    One of the reasons we started this team blog was to get your comments (spurred by our tips and tricks), so it's exciting to see more folks chime in. Let me just take a moment to fan the flames…
     
    We're listening
    We're always open to feature requests to help us plan for future versions. And we're also interesting in blog post suggestions, which we'll try to post on quickly. If you have kudos, well of course they're always welcome. So leave a comment to let us know what you're thinking!
     
    Need support?
    If you need help solving a specific question, you're better off in the newsgroups, where both the product team and InfoPath MVPs are on watch and where there's a large archive of other like-minded questions. For more general issues or something you suspect is a bug, check out the support center. And for common tasks and basic overviews Office Online is your best bet.
     
    Thanks!
    - Ned
Page 1 of 1 (8 items)