Microsoft InfoPath 2010
The official blog of the Microsoft InfoPath team

  • Microsoft InfoPath 2010

    InfoPath and Yukon: The Details

    • 9 Comments

    In a recent post, I touched upon the reasons why you might want to go with SQL Server XML columns as the storage for your InfoPath forms. In this article, we'll talk about actually making it work.

    InfoPath's strength is working with XML data sources: web services. In the implementation below, we'll write a simple web service that will help us retrieve and submit the data to Yukon.

    Scenario

    Build a resume database for the HR department. We want to store highly structured resumes in a database. Highly structured here is the opposite of freeform: a resume in our scenario isn't a blob of text; we have the graduation date, employment dates, actual titles and other things parsed into data structures.

     

    Data Structure

    We will store candidate records as XML blobs in a Yukon XML column. Each resume will be stored as a separate record; each record will also have a primary key - a JobCandidateID - to simplify our development. We'll define only one table, called JobCandidate:

    Populate the table with a few Resume XML files that all satisfy the same schema. Store the schema somewhere where the web server can access it.

     

    Core Implementation in English: we'll write a web service as a middle tier between SQL Server 2005 and the InfoPath form. This web service will have two methods:

    1) GetCandidateRecord: given a JobCandidateID (an integer), return a DataSet (for our purposes, an XSD-typed XML blob) that contains the candidate record. Give me the job candidate ID, I'll give you his resume.

    2) UpdateCandidateRecord: take a JobCandidateID (an integer) and a Resume (an XML document), and update the resume of the candidate with that particular ID to the resume passed in as a second parameter. Nothing fancy, really.

     

    Core Implementation in C#

    I promised you two methods, here they are. First, GetCandidateRecord.

    [WebMethod]
    public DataSet GetCandidateRecord(int JobCandidateID)
    {
        DataSet result = null;

        using (SqlConnection conn = new SqlConnection(connString))
        {
            conn.Open();
            SqlCommand command = conn.CreateCommand();
            command.CommandText = @"
                SELECT Resume
                FROM "
    + tableName + @"
                WHERE JobCandidateID = @x"
    ;           
            command.Parameters.Add("@x", SqlDbType.Int);
            command.Parameters[0].Value = JobCandidateID;
            SqlDataReader reader = command.ExecuteReader();

            if (reader.Read())
            {
                DataSet ds = new DataSet();
                ds.ReadXmlSchema(@"C:\Inetpub\wwwroot\infopath_yukon\Resume.xsd");
                XmlDataDocument xd = new XmlDataDocument(ds);
                xd.Load(new StringReader((string)reader.GetValue(0)));
                result = xd.DataSet;
            }
            conn.Close();
            return result;
        }
    }

    Things are fairly straightforward here:

    - Open a SqlConnection using ASP.NET credentials (make sure the ASPNET user has read/write rights to the database).

    - Build a simple SELECT statement to return a resume. Recall that the resume is just an XML document stored as-is in the database.

    - Cast the resume dataset into a typed dataset by applying a schema stored somewhere on the web server. Oh, I forgot to tell you - you need a schema :-). Why? InfoPath form needs to know what to expect from the web service, and while InfoPath can infer the shape of the data from the instance, this method is very much error prone. For example, how can InfoPath know of a repeating structure if only one instance was present in a sample XML document? How about choice or optional structures? Because of all of these reasons, you need to provide a typed dataset through your web service.

    - Return the typed dataset for the Resume record.

     

    Next, let's look at UpdateCandidateRecord.

    [WebMethod]
    public void UpdateCandidateRecord(XmlDocument xml, int JobCandidateID)
    {
        using (SqlConnection conn = new SqlConnection(connString))
        {
            conn.Open();
            SqlCommand command = conn.CreateCommand();

            command.CommandText = @"
                UPDATE "
    + tableName + @"
                SET Resume = @x
                WHERE JobCandidateID = @y"
    ;
            command.Parameters.Add("@x", SqlDbType.Xml);
            command.Parameters[0].Value = xml.InnerXml.ToString();
            command.Parameters.Add("@y", SqlDbType.Int);
            command.Parameters[1].Value = JobCandidateID;
            command.ExecuteNonQuery();
            conn.Close();
        }
    }

    - Open a SqlConnection

    - Build a simple UPDATE statement to save the resume for a given candidate. Note that you must use SqlCommand Parameters: just concatenating the XML blob won't do.

    - Execute the UPDATE statement. Note that we are replacing the entire resume with the new one; no partial updates are done. This means that simultaneous editing of Resume records won't be possible.

     

    Basic Form Template

    Now that the web service is set up, we can easily build a form template based on it. The template may or may not be browser-enabled; the method described here works with both. Just launch InfoPath designer, and pick "start from web service" as your data source. Specify GetCandidateRecord as the "receive" piece of the web service, and UpdateCandidateRecord as the submit part.

    InfoPath will ask you for sample JobCandidateID values for the receive web service; since our database already has a few Resumes, we can type in the JobCandidateID for one of them. You may be wondering - wait, I thought InfoPath won't do the schema inference by example! It won't - the dataset returned by your web service will contain a schema (that's why we called DataSet.ReadXmlSchema() in GetCandidateRecord), and InfoPath will use that schema to build your data source tree.

    After you've gone through the initial data connection setup, you'll notice that your main data source tree is correctly populated with the data types from your schema. Complex structures should show up just fine - repeating, optional, choice structures, non-string datatypes, XSD validation... And the Submit button should be configured to save the modified Resumes back to SQL Server.


    FAQ

    1. Why do we have to use a custom web service, and not built-in Yukon web services?
    There are unfortunate technical limitations that currently require you to write a custom web service to work with SQL Server 2005 in a manner described above. The web service is, as you saw, very easy; we know that this is something that can be made better, and will consider addressing this in future versions of InfoPath and SQL Server.

    2. Why not XSD-typed XML columns?
    When InfoPath submits datasets to the web service, it adds dataset tracking information; while you can add optional attributes to your InfoPath-generated schema and upload it to Yukon, this would complicate maintenance quite a bit.

    3. What other resources are available on the topic?
    Be sure to check out this article by S.Y.M. Wong-A-Ton.

    Alex Weinstein
    Program Manager

  • Microsoft InfoPath 2010

    Enforcing unique values in a repeating list

    • 3 Comments
    Have you ever created a form which allows the user to choose items from a list and you wanted to make sure the user doesn't choose the same item twice?  If you've got InfoPath 2007 you can use the new Multi Select List Box, but if you've got InfoPath 2003, you're still in luck, this blog entry is for you!
     
    Note: You should be familiar with XPath expressions before preceding.
     
    Let's start with a repeating table with a dropdown control bound to a secondary data source.
     
     
    There are a few choices when it comes to enforcing unique values selected by the user:
    1. Only show values that have not already been selected by the user.
    2. Show a validation error when the user selects something which has already been selected.
    3. Write code using the Changing event.
     
    This blog entry will cover both options 1 and 2.
     
    Option 1 - Only show values that have not already been selected by the user
     
    Only showing certain values implies that a filter is being applied to the dropdown.  To apply a filter, click the Filter Data… button when selecting the entries for the dropdown to show the condition builder.  Unfortunately, there is no UI in the condition builder to build an expression that means "don't show anything that is already in the list".  Thus, we'll have to construct this manually by selecting The Expression.
     
     
    You might be tempted to put the following expression:
    . != xdXDocument:get-DOM()/my:myFields/my:items/my:item/my:product
    This will return true if any one value from the list matches the current value.  In other words, this condition will always return true if there are two entries in the list which are different.  (Definitely not what we are looking for)
     
    The correct condition is a slight adjustment to the former expression:
    not(. = xdXDocument:get-DOM()/my:myFields/my:items/my:item/my:product)
    This will only return true if none of the values from the list matches the current value.  In other words, only values that are not in the list will be displayed.
     
    Preview the form and you will see that the dropdown only lists the products that have not already been selected.
     
     
     
    Option 2 - Show a validation error when the user selects something which has already been selected
     
    The only way this will work properly is if we add a hidden calculated field along with the product selection.
    (The reason for this is a bit too complex to explain here, so it'll have to wait for another time.)
     
     
    The formula for the unique field is the following:
    not(../my:product = (../preceding-sibling::my:item | ../following-sibling::my:item)/my:product)
    This will set Unique to true if and only if the product isn't already selected preceding or following the current item.
     
    The next and final step is to use data validation on the dropdown to show an error.
     
     
    Preview the form and you will see that the dropdown will show a validation error if the items are not unique.
     
     
    - Gary
    Software Development Engineer
  • Microsoft InfoPath 2010

    Introducing Horizontal Repeating Tables

    • 6 Comments
    InfoPath 2007 adds horizontal repeating table to the control toolbox for when you want data to be entered or displayed in a structured, tabular format, and when you want users to be able to add additional columns instead of rows.
     
    For example, you might use a horizontal repeating table to collect sales data for each quarter:
     
    Making it wrap
    When designing your form template, horizontal repeating table looks like a composite control -- it’s made from a horizontal repeating section and layout tables (I'll cover horizontal repeating section in my next post). Horizontal repeating table can be configured to wrap or scroll. By default, it will wrap to the next line, to provide a better printing experience.
     
    You can change the behavior of the control by resizing the layout tables; for example, to change the wrapping point, resize the rightmost border of the layout table:
     
     
    This will allow only two instances of the repeating column to fit on one line; the next two will go to the next line, and so forth:
     
     
    Making it scroll
    You may want to set an upper bound on the amount of real estate that a horizontal repeating table can take up; in that case, you need to make the control scroll. User experience will then be similar to the following:
     
     
    To achieve such behavior, you need to make the following modifications to your form template:
    1. Encapsulate the repeating section component of the horizontal repeating table in a scrolling region.
    2. Set the properties on the scrolling region:
      • Show horizontal scroll bars: always
      • Show vertical scroll bars: never
      • Wrap text: unset
      • Margins: all zero
      • Padding: all zero
      • Size: appropriate height and width
      • Borders: no borders
    3. Resize the rightmost border of the layout table that contains the horizontal repeating table to match the border of the scrolling region.
     
    When you’re done, your form template will look similar to the following in Design mode:
     
     
    Scrolling is often desirable for electronic forms, but is not ideal for printing. If you want to achieve both, you need to use scrolling in the view that users will see when filling out the form and wrapping in an associated printable view.
     
    Data binding of a horizontal repeating table is identical to that of a regular repeating table or section.  Horizontal repeating tables support conditional formatting, data validation, rules, calculations, other InfoPath data features that a regular repeating tables support.
     
    Note that horizontal repeating tables are only supported in InfoPath 2007 client.
     
    - Alex Weinstein
    Program Manager
  • Microsoft InfoPath 2010

    Dynamic Pictures

    • 6 Comments
    When designing a feature-rich InfoPath form template, it is sometimes necessary to provide a dynamic image in response to user action. InfoPath picture control hides treasures that will help you satisfy such a requirement. In this article, we will explore a technique that allows you to make this happen without writing any code.
     
    Here is our scenario: build a hardware order form for the telecommunications department. In the form, we would like to let the user choose the phone that they want to order, and show them a picture of the phone as soon as they select it.
     
     
    The following steps will make this possible:
     
    1. Place pictures of available phones in a shared location; let's call it http://mysite/phones/photos/. Pictures are named according to phone ID's - for example, 1.jpg, 2.jpg, 3.jpg, etc.

    2. Insert a picture control. When you do so, InfoPath will ask whether you want the picture to be included into the form, or if you want it to be linked. Choose the second option.
    3. Take a look at the node that was just inserted into your data source by going to View | Data Source. Let’s call the new node hyperlinkDataSource; it’s a node with data type "hyperlink".

    4. Insert a text box that’s also bound to hyperlinkDataSource.

    5. Preview the form. Use the picture control to attach the image. Observe how the path in the text box changes to reflect the path of the image you just attached. Try changing the value of the text box to point to a different picture. Note how the picture control displays the new picture when you tab out of the text box.

      Now, we want this step to happen programmatically, when the user selects the phone from the dropdown of available phones.

    6. Create a phone picker dropdown; labels in the dropdown will show phone names, and values will contain phone ID's that correspond to file names we used in step 1. The simplest way to do this is to enter the items manually; don't forget to include the default "pick a phone" item.




    If you want to get fancy, you can use a secondary data source - web service - to provide the list of available phones.

    1. Create a rule on the phonePicker node: set the value of hyperlinkDataSource to

      concat("http://mysites/phones/photos/", phonePicker, ".jpg")

    2. Go to control properties for the new picture control; uncheck the “Allow users to browse for new pictures” property.

    We're done! Preview the form and try selecting a few phones from the dropdown.
     
    Picture control is available in both InfoPath 2003 and 2007, however it is not supported in browser-enabled form templates.
     
    Alex Weinstein
    Program Manager
  • Microsoft InfoPath 2010

    Having more control over Page Breaks using Conditional Formatting

    • 1 Comments
    When printing forms, sometimes it might be desired to have more control over where Page Breaks should occur. For example, you might want a Repeating Table to start printing on a new page once it has reached a certain number of rows or you might wish to provide a way for users who are filling out forms to be able to insert/remove Page Breaks in certain locations of the form. You can accomplish this using Page Breaks (available with SP1) with Conditional Formatting.
     
    Example 1: Allow users to insert a Page Break when a Checkbox is checked
    1. In Design mode, insert a Checkbox Control, type "Insert Page Break" next to the checkbox.
    2. Insert a Section Control (From the Control Task Pane, click on "Section")
    3. Within the Section Control, insert a Page Break (Place the cursor inside of the Section Control you just inserted and from the menu Insert | Page Break)
    4. Double click on the Section Control to open the Section Properties dialog. Select the Display tab and click on the Conditional Formatting button.
    5. Click  Add... to set a new condition, which will keep the Page Break "hidden" unless the checkbox is checked, to do this: Select the name of the checkbox in the first condition drop-down and set the condition "is equal to FALSE". Check the "Hide this Control" checkbox and close all open dialogs by clicking "Ok"
    6. You can test your form by clicking on the Preview Form button, in the toolbar.
    Example 2: Start printing a Repeating Table in a new page once it has more than 3 rows
    1. In Design mode, insert a Section Control (From the Control Task Pane, click on "Section")
    2. Within the Section Control, insert a Page Break (Place the cursor inside of the Section Control you just inserted and from the menu Insert | Page Break)
    3. Place the mouse cursor beneath the Section Control and insert a Repeating Table (From the Control Task Pane, click on Repeating Table).
    4. Double click on the Section Control to open the Section Properties dialog. Select the Display tab and click on the Conditional Formatting button.
    5. Click Add... to set a new condition, which will keep the Page Break "hidden" unless the number of rows in the "Repeating Section" exceeds 3, to do this: Select  "The expression" in the first condition drop-down and type the following XPath expression referring to the Repeating Table, "count(../my:group2/my:group3) <=3" in the text field next to it. Check the "Hide this Control" checkbox and close all open dialogs by clicking "Ok"
    6. You can test your form by clicking on the Preview Form button, in the toolbar.
     
  • Microsoft InfoPath 2010

    Do You Love Access? We do too!

    • 3 Comments

    And that's why there's all the new-and-cool documentation about how to make your InfoPath forms work well with Access:

    And a few bonus articles, also from our friends in the documentation team:

    Happy Friday!
    Alex

  • Microsoft InfoPath 2010

    Move Up/Move Down

    • 4 Comments

    One stumbling block for developers coming up to speed on InfoPath is that the SDK documentation leads you to the edge of the XML cliff and then goes mysteriously quiet. For web developers who have programmed applications with the MSXML SDK for manipulating XML this isn’t a problem – they brought their parachute with them and happily jump off. For others, this can be a little intimidating.

    Here’s a good way to get started manipulating the XML DOM directly – let’s add “Move Up” / “Move Down” buttons to a Repeating Table so you can re-order the items.

    First off, let’s build the view:

    1. Fire up InfoPath 2003 and start a new blank form
    2. Insert a Repeating Table from the Controls task pane
    3. Delete the text box in the last column, and add two buttons in that cell instead
    4. Pull up the properties on first button and give it the label “5” and the ID “MoveUp”
    5. Pull up the properties on second button and give it the label “6” and the ID “MoveDown”

     At this point, you’re thinking “5 and 6???”

    1. Select both buttons (Click the first, and Ctrl+Click the second)
    2. On the Font drop-down on the toolbar, select Marlett. Then take a look at the buttons.

    (Sneaky, huh? Glyphs from this font are used by Windows to render all sorts of UI elements like the Minimize/Maximize Window buttons. This is a handy way to avoid having to use images for simple things like arrows.)

    Now that we have it looking pretty, let’s add the event handlers for the buttons. We’ll build on the logic from this blog entry to figure out which instance of the buttons was clicked.

    1. Pull up the properties on the first button and click Edit Code – paste the following into the editor:

    Sub MoveUp_OnClick(eventObj)

    ' Write your code here

     

       Dim oItem, oParent, oPrevious

      

       Set oItem     = eventObj.Source

       Set oParent   = oItem.parentNode

       Set oPrevious = oItem.previousSibling

      

       If Not ( oPrevious Is Nothing ) Then

             

              oParent.removeChild oItem

             

              oParent.insertBefore oItem, oPrevious

             

       End If

     

    End Sub

    The logic here is straightforward:

    • Grab the context node of the button (the row of the table, in our case)
    • If there is another item before the context node, remove the context node from the tree and re-insert it before the previous node
    1. Pull up the properties on the second button and click Edit Code – paste the following into the editor:

    Sub MoveDown_OnClick(eventObj)

    ' Write your code here

     

       Dim oItem, oParent, oNext

      

       Set oItem   = eventObj.Source

       Set oParent = oItem.parentNode

       Set oNext   = oItem.nextSibling

      

       If Not ( oNext Is Nothing ) Then

             

              oParent.removeChild oNext

             

              oParent.insertBefore oNext, oItem

             

       End If

     

     

    End Sub

    The logic here is similar:

    • Grab the context node of the button (the row of the table, in our case)
    • If there is another node after the context node, remove the it and re-insert it before the context node

    Almost done – let’s just use a little Conditional Formatting to disable the buttons when the item is the first or last in the list:

    1. Add a conditional for the first button which reads:

      if “The expression” “position() = 1” then Disable this control
       
    2. Add a conditional for the second button which reads:

      if “The expression” “position() = last()” then Disable this control

    Now try it out.

    As an aside, this was the author’s first foray into VBScript. Although I cut my teeth in Applesoft BASIC I’ve done most of my programming in C-style languages (C, C++, C#, Perl, Java). Did I do anything silly?

  • Microsoft InfoPath 2010

    Debugging Sandboxed Code in InfoPath 2010 Forms

    • 13 Comments

    In this video demo, Phil Newman from the InfoPath program management team shares some tips and tricks for debugging InfoPath forms with sandboxed code on SharePoint server 2010.

    Get Microsoft Silverlight

    Here is this link to the ULS viewer tool that is used in the demo:

    Filters:

    • Process=SPUCWorkerProcess (for administrator-approved forms, filter on the W3WP process)
    • Message=Exception thrown from business logic
  • Microsoft InfoPath 2010

    Moving fields in the data source

    • 13 Comments
    As most folks figure out quickly, InfoPath doesn't support drag-and-drop of fields in the data source. There are a lot of technical reasons for this, and even a usability concern that people won't realize they can drag fields onto the form as controls if we also allowed them to drag fields around in the data source. But we've heard enough feedback that changing that has made it onto the long list of possible features for future releases. Keep the feedback coming!
     
    So how do you move fields groups in the data source?
    One way is to right-click the field or group and select "Move Up" or "Move Down". This is great for novices because it's discoverable, but it's a painful number of clicks if you're an expert who has to move a lot of fields in many forms.
     
    A trick for the keyboardist
    The fastest way to move a field or group a long distances is:
    1. Open the data source task pane
    2. Type the "F6" key
    3. Click tab until a field in the data source is highlighted in orange
    4. Use the Up/Down arrow keys to select the field you want to move
    5. Hold down the CTRL key and use the Up/Down arrow keys to move the field
     
     
    Note that this only moves the field in order, it won't move it as a child of a different group. To do that you still need to right-click the field and select "Move".
     
    Hope that helps!
    ned
  • Microsoft InfoPath 2010

    REMINDER: Learn about InfoPath 2010 in Free Web Casts

    • 0 Comments

    If you want to learn more about InfoPath and SharePoint 2010 directly from the Microsoft product team, then sign up for the InfoPath 2010 Academy Live Series.

    There are 2 remaining sessions in the series. The next session “Form-Driven Mashups using InfoPath and SharePoint 2010", presented by Nick Dallett, an InfoPath program manager lead, will take place on Wednesday, April 7th from 8:30 AM to 10:00 AM (PST).

    If you missed our first 2 sessions, “An introduction to SharePoint applications using InfoPath 2010” and "Building SharePoint Applications with InfoPath 2010", you can view them on demand here. Just click the “Register Now” button.

    This is a great opportunity to learn all about our new features and scenarios directly from the product team, so sign up now!

    infopath_banner_ad_1_3

  • Microsoft InfoPath 2010

    Powerful Declarative Logic: Phone Number Parsing

    • 10 Comments

    When entering phone numbers in InfoPath, you can validate that it is a phone number easily enough (Data Validation->field1 “matches pattern” Phone number), but what do you do if the input does not match that pattern? Asking users to exactly enter the format “(000) 000-0000” may be a little constraining. Therefore, you may want a rule so that any combination of spaces, dashes, parenthesis and 10 digits will be reformatted nicely.  Below I will describe how to do this in a rule, although you could do the same in business logic. 

    For the rule’s action, you would want to use translate, substring and concat functions.  Logically, as your first action you would translate to remove all unwanted characters (spaces, dashes and parenthesis).  Then, as your second action substring and concat everything. 

    However, you cannot break it into two actions.  When the translate is executed, it changes the text field.  InfoPath immediately reruns the rule on that field (even before the rest of the actions are run from the first time).  For the second run of this rule, the conditions will all pass (as you would have a number like “0123456789” due to the translate that already happened), and the translate action would be run again.  This will happen repeatedly and causes a recursion error. 

    Therefore, you would need to do this all in one action (the rule will be rerun here, but the conditions will not pass since it will match the phone number pattern).

    On your text box, you will need:

    1. One condition with 3 parts:

    - Field “does not match pattern” phone number “and”

    - Without the “()- “ characters, it has length 10:
    “The expression” string-length(translate(., "()- ", "")) = 10 “and”

    - There are no characters other than digits and “()- “ characters
    “The expression” string-length(translate(translate(., "()- 0123456789", "")) = 0

    2. One action that removes (), - and spaces; takes substrings; and concatenates it all together at once:

    Set a field’s value “.” to concat("(",substring(translate(., "()-", ""), 1, 3), ")", substring(translate(., "()-", ""), 4, 3), "-", substring(translate(., "()-", ""), 7, 4)))

    And you're done! Note that this technique will work in InfoPath 2003 and 2007, and it is supported in browser-enabled form templates. Download the form template that has this trick implemented; make sure to save it to your desktop.

    Nicholas Lovell
    Software Design Engineer
    Alexei Levenkov
    Software Design Engineer

  • Microsoft InfoPath 2010

    Getting the XPath without straining your brain

    • 5 Comments
    Yesterday I talked about using System.Xml in the new object model. My code examples included a key part of the InfoPath programming model: looking up fields in the data source using XPath so that you can set and get values.
     
    Unfortunately, figuring out the absolute XPath to a field can be a pain.
     
    Fortunately, we've made that easy in InfoPath 2007.
     
    Here's how
    Right click the field in the Data Source task pane and click Copy XPath
     
    Now you can paste the XPath into your code and be on your merry way.
     
    Hope that helps,
    Ned
  • Microsoft InfoPath 2010

    New InfoPath content on the web

    • 7 Comments

    I wanted to take a moment to recognize the great work of the Microsoft writers and editors who have been cranking out InfoPath content over the last few months.  While we in the product team have clicked over into Office 14 mode, they have continued to serve customers by creating Office 2007 content – everything from video demos to highly technical developer content.  Here’s some of the content that has been released since RTM.  Thanks to Anneliese Wirth, Arsenio Locsin,  Amy Miller, Anthony Labriola,  Kelley Vice, Tonda Kiffin, David Longmuir, Roger Haight,  and Mark Roberts for getting this information into the documentosphere!

     

     

    November 2006:

    -          Demo: Convert a Word document into an InfoPath 2007 form template

    -          Demo: Use InfoPath e-mail forms to view data in Outlook 2007

    -          Demo: View the business logic in an InfoPath 2007 form template

     

    April 2007:

    -          Article: How to: Share InfoPath 2007 Template Parts and ActiveX Controls

    -          Article: Hosting the InfoPath 2007 Form Editing Environment in a Custom Web Form

     

    May 2007:

    Article: How to: Evaluate and approve a form template

    Article: Guidelines for Creating InfoPath 2007 Converters

     

    June/July 2007:

    -          Article: Working with XML Data Using the XPathNavigator Class in InfoPath 2007 Form Templates

    -          Article: Guidelines for using colors, fonts, and images in a form template

    -          Article: Converting InfoPath 2003 Managed Code to the New InfoPath 2007 Object Model

     

    In addition some content that has been missing from MSDN has been re-published:

     

    -          InfoPath 2003 SDK:   http://msdn2.microsoft.com/en-us/library/bb190871(office.11).aspx

    -          InfoPath 2003 technical articles: http://msdn2.microsoft.com/en-us/library/bb191012(office.11).aspx

     

    We also have some excellent articles written by David Gerhardt of 3Sharp

    -           Developing InfoPath 2007 Managed-Code Solutions.

    -          Pulling CRM Data into InfoPath 2007 Browser Forms 

     

    And finally, InfoPath MVP Ben Walters just posted a code sample which shows how to limit the contact selector control to  single selection:  http://msmvps.com/blogs/benwalters/archive/2007/07/13/contact-selector-the-good-and-the-bad.aspx

     

    Enjoy!

  • Microsoft InfoPath 2010

    Advanced server-side authentication for data connections, part 2

    • 4 Comments

    In the first part of this series I introduced the concepts involved in three tier authentication. Now let's drill into the details and work with some code.

     

    Using Office Single Sign-on  with individual mapping

     
    An Office Single Sign-on (SSO) application definition, can be set up in one of three ways:  individual, group, or group using restricted credentials.  An InfoPath form published to the server can use either of the first two.  However, in order to use individual credentials, the SSO database must contain a separate username and password for each user who connects to the form.  A typical server application would check whether the connecting user had credentials in the database, and redirect to a credentials management page when appropriate to allow the user to enter their credentials.  While InfoPath Forms Services does not do this generically for forms that use SSO, it’s possible to implement a solution for an individual form or a set of forms the same way an Office Server application would, by using the Pluggable SSO API.
     
    The general approach is to have users link to an ASP.NET page rather than directly to the form.  The ASP.NET page attempts to get the user’s credentials from the SSO database, and based on the result either redirects to the form or to a credential management page  which allows the user to input their credentials.
     
    Enough talk.  Let’s get our hands dirty.
     
    My code assumes that you have defined an SSO application definition called MyApp and that the application is set up to use individual credentials.  I also assume that that have an administrator-approved form template called myform.xsn activated on the site collection, and that the form uses one or more data connections that reference the MyApp application.
     
    In order to use SSO to make the data connection, you must be using data connection settings in a UDC file on the server.  To add the reference to the MyApp app definition, you add an Authentication element to the UDC file.  The authentication element must be the last subelement of the ConnectionInfo element, and it looks like this:
     
    <udc:Authentication>
      <udc:SSO AppId="MyApp" CredentialType="NTLM"></udc:SSO>
    </udc:Authentication>
     
    To create the redirector page, the first thing is to add a new ASP.NET page to the root site of your SharePoint server.  Find the home directory of your root site by opening up Internet Services Manager and checking the Home Directory page of the properties page for the web application.  Open this web in Visual Studio and add a new ASP.NET page.  In the properties  for the page, enable session state.  Finally, add a reference to the Microsoft.SharePoint.Portal.SingleSignon namespace.
     
    Once this is done, the new page should look like this:
     
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="SingleSignonRedirector.aspx.cs" Inherits="SingleSignonRedirector" EnableSessionState="True" %>
    <%@ Import Namespace="Microsoft.SharePoint.Portal.SingleSignon" %>
     
    Open the code file for the page, and add a using statement for the SingleSignon namespace
     
    using Microsoft.SharePoint.Portal.SingleSignon;
     
    The code itself is relatively straightforward.  Start by using the pluggable API to get a reference to the installed SSO provider.
     
    ISsoProvider provider = SsoProviderFactory.GetSsoProvider();
     
    (this call will fail if no provider is installed, or if the Single Signon service is not running)
     
    Your page will run under the credentials of the user attempting to access the form, so when you call GetCredentials, SSO will return a credential for that user, or throw SingleSignonCredsNotFoundException if the credential does not exist.
     
    try
    {
       SsoCredentials credentials = provider.GetCredentials("MyApp");
    }
    catch (SingleSignonCredsNotFoundException)
     
    In the event that the credentials are not found, you can get the URL of the credentials management page for the installed provider.
     
    Uri CredentialsManagementUrl = provider.GetCredentialManagementURL("MyApp");
     
    Now, at this point you could simply redirect to the credentials management URL.  However, you would miss part of the magic of the credentials management page.  The credentials management page supplied with the Office single Sign-on provider will redirect back to the referring page once the user has entered valid credentials.  I chose to handle this by presenting a link to the user to allow them to click through to the credentials management page.
     
    Response.Write("<P>Before you can access this form, you must enter credentials to access backend data.</P>");
    Response.Write("<P><A href=\"" + CredentialsManagementUrl.ToString() + "\">Click here to enter your credentials</A></P>");
    Response.End();
     
    An alternate approach could be to add the HTTP referer header to the response before performing a redirect.  Either way, once the user has entered their credentials, the redirector page will be called again.  This time the GetCredentials call will succeed, and the page will redirect on to the form.
     
    Here’s the complete code-behind for the page:
     
    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using Microsoft.SharePoint.Portal.SingleSignon;
     
    public partial class SingleSignonRedirector : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            ISsoProvider provider = SsoProviderFactory.GetSsoProvider();
            try
            {
                SsoCredentials credentials = provider.GetCredentials("MyApp");
            }
            catch (SingleSignonCredsNotFoundException)
            {
                Uri CredentialsManagementUrl = provider.GetCredentialManagementURL("MyApp");
                Response.Write("<P>Before you can access this form, you must enter credentials to access backend data.</P>");
                Response.Write("<P><A href=\"" + CredentialsManagementUrl.ToString() + "\">Click here to enter your credentials</A></P>");
                Response.End();
            }
            catch (Exception ex)
            {
                Response.Write("<P>Single Sign-on returned an error:  " + ex.Message + "</P>");
                Response.End();
            }
     
            // Good to go - on to the form
    Response.Redirect( "http://myserver/formservertemplates/myform.xsn?openin=browser" );
           
        }
    }
     
    Getting jiggy with it
    For a real-world application, there are a few more things I might do to this page to round out the implementation.  Depending on the needs of the specific application, one or more of the following might apply:
     
    • Loop through multiple Application IDs to allow the user to enter credentials for each
    • Attempt to log on the user using the SSO credentials to verify that the credentials are valid and have not expired
    • Use this code in a page which hosts the form in question using the XmlformView control
    • Create a generic page which takes the URL to the form and the Application ID as query parameters
    With a little bit of ingenuity, you can use this approach to create a seamless end-to-end experience to satisfy any scenario.
     
    In my next and final post in this series, I'll talk about how to use a web service proxy for authentication. Stay tuned!
     
    - Nick
    Program Manager
  • Microsoft InfoPath 2010

    Hosting InfoPath forms in a custom ASPX page

    • 3 Comments

    Many of you saw a detailed MSDN article on embedding an InfoPath XmlFormView control into a custom ASP.NET page. But - there's more to it. I came across an interesting blog post that talks about embedding a browser-based InfoPath form into a webpart. Here's another post of someone who got it to work, with nice screenshots.

    Alex Weinstein
    Program Manager

  • Microsoft InfoPath 2010

    Displaying Contextual Help in a Custom Task Pane

    • 8 Comments

    With all the wonderful features in the new Office apps, it's easy to get lost!  InfoPath is no exception, and when you make clever use of the new features, you'll want to make sure that users understand how your form is supposed to work.  Wouldn't it be great if you could display contextual help information as the user navigates to fields in your form.  With the "Context Changed" event, you can execute custom code when the user filling the form causes the context node to change.  This will fire when the user focuses a control bound to a different DOM node than the current context node.

     

    Files you'll need

    The solution we provide here uses some resource files.  Download the attached files to accomplish the scenario.

    1. "CustomTaskPaneHelp.htm" - The HTML file that will be displayed in the custom task pane.  We will manipulate this document at runtime from custom form code to display the contextually appropriate help information.  Just update the styles in this file to change the appearance of the contextual help in the custom taskpane.

    2. "Help Strings.xml" - This file is a basic xml file that contains mappings from local node names to the title and help contents for the node.  This file will be consulted to retrieve the help information to be displayed in the custom task pane.

    3. "CustomTaskPane.cs" - This helper class wraps the HtmlTaskPane object to access elements in the custom task pane.  This will be added to your VSTA project.

    4. "FormCode.cs" - This contains the code to integrate the custom taskpane into the form template.

    Note that this method works in InfoPath 2003 and 2007, but this tutorial will walk you through the steps in for InfoPath 2007 - the UI is slightly different in 2003, but you can still make it work. Since task panes are a rich-client only feature, this method is not supported in browser-enabled form templates.

     

    Construct your help resource file

    Assuming you've designed your form template already, you'll have a nicely populated data source, replete with variously named nodes.  Now add contextual help data for nodes in the main and secondary data sources:

    1. Open the "Help Strings.xml" file in notepad (or another text editor.)

    2. Add a "Help" element for the data source node:

    • Set the "nodeName" attribute's value to "<node prefix>:<Name in Data Source Pane>"
    • Set the "Title" element's value to the heading that you want to display for this node's contextual help.
    • Set the "Contents" element's value to the body of this node's contextual help.

    3. Repeat step 2 for all nodes for which you want to display contextual help so that you have something like this:

    <?xml version="1.0" encoding="utf-8" ?>
    <HelpStrings>
       <HelpString>
          <Help nodeName="my:TextField">
             <Title>Text Field</Title>
             <Contents>Help for my text field.</Contents>
          </Help>
          <Help nodeName="my:RichTextField">
             <Title>Rich Text Field</Title>
             <Contents>Help for my rich text field.</Contents>
          </Help>
       </HelpString>
    </HelpStrings>

     

    4. Save the file to a shared location

    NOTE:  If you want to be able to update this help data without having to re-deploy the form template, the shared location should be accessible to all users that will fill out the form.  If, on the other hand, you do not care about that, then you can just save the file locally and add it as a resource file to the form template.  See below…

     

    Add the data source that will provide your contextual help data

    Now that you're help strings are all set, we need to add a reference to the help strings so that the form template can access them.  We'll do this by adding a data connection to query the xml file from a shared location or resource file.

    1. Tools >> Data Connections >> Add

    2. Select Receive Data, then XML Document

    3. Specify the location of the help strings document (Help Strings.xml)

    • If, as noted above, you want to include the help strings as a resource file in the form template, just click "Next >". Including the file as a resource file guarantees that it will always be accessible to the form template, but the form template will have to be updated if you need to change the help strings.
    • If, on the other hand, you would like to access the help strings file from a shared network location or web server, then select "Access the data from the specified location" and then click "Next >". Accessing the file from a shared location may fail if the shared location is unavailable, and there may be some delay due to network traffic.

    4. Check the "Automatically retrieve data when form is opened" check box and click "Finish" / "Close".

     

    Enable the custom task pane in your form template

    Custom task panes are not enabled by default.  We'll specify that the custom task pane should be displayed, and its content should be rendered from the "CustomTaskPaneHelp.htm" file.

    1. Tools >> Form Options >> Programming

    2. Check the "Enable custom task pane" check box. Type a name for the custom task pane in the "Task pane name" field.

    3. Add the "CustomTaskPaneHelp.htm" file as a resource file.

    • Click Resource Files >> Add…
    • Browse to the "CustomTaskPaneHelp.htm" file and click Open / OK.

    4. Select "CustomTaskPaneHelp.htm" from the "Task pane location" drop-down list.

     

    Add the code to manage the context change and display the contextual help information

    1. Tools >> Programming >> Context Changed Event; this will create the VSTA project and insert the "Context Changed" event handler.

    2. Add the "CustomTaskPane.cs" file to your project

    • Right-click the top-level project node.
    • Click "Add" >> "Existing Item…"
    • Browse to the "CustomTaskPane.cs" file and click "Add".
    • IMPORTANT: Edit the Namespace of the "CustomTaskPane.cs" file to be the same as that of your form code file.

    3. Integrate the code in the attached "FormCode.cs" file into your VSTA project.  Make sure you copy the contents of the "FormEvents_ContextChanged" method, as well as the private properties and variables.

    4. Build and save your form template.

     

     

    Make the form template full trust

    1. Tools >> Form Options >> Security and Trust
    2. Uncheck the "Automatically determine security level" checkbox. Select the "Full Trust" radio button.
    3. Click "OK"
    4. Save and publish the form template. You will need to publish the form template as an installable form template (.msi) or digitally sign the template; detailed instructions are here.

    Now, when users fill out your form, contextual help will be displayed for each node as the user clicks on a control bound to it.  As long as you've included help information in the help strings file, you'll see the help information in your custom task pane!

    Forrest Dillaway
    Software Design Engineer in Test

  • Microsoft InfoPath 2010

    Best Practices for Rules

    • 2 Comments
    My forms have a bad habit of accumulating more and more rules as I add more and more functionality over time, so I came up with a set of guidelines to keep those rules clean and orderly.
     
     
    Remember that there are four places to add rules
    1. On Button Click (in Properties dialog)
    2. When values change (in Controls and Data Source Properties)
    3. On Submit (in Submitting Forms dialog)
    4. On Load (in Form Options | Open and Save section)
     
    Give your rules names for the scenario they capture
    Good names will summarize their conditions/actions in a more friendly way: eg "Submit using multiple data connections", or "Cancel query if expenses too high".
     
    Group rules by condition, but separate actions without conditions
    If more than one action has the same condition, put them together so you can edit the condition only once. Otherwise, put each action in its own rule, so you can easily reorder them independently.
     
    Use "Stop processing rules" to save retyping conditions
    If there's a case where you don't want to run any of your rules, add a rule that checks that case. It doesn't need to have any actions, just check the box to stop processing rules and put the rule before any of the other rules that would also check that case. For example, if you want to skip some submit logic if the expenses in the form are less than 100, put that condition in its own rule before your submit logic, and just have it stop the rules.
     
    Use dialog messages to debug while developing
    Dialog messages are great for tracing your rules at runtime, but are usually jarring while filling out the form. If you have a condition message to show, use conditional formatting instead to hide/show a section/expression-box with the message. You can even make the message dynamic by having the expression box look up a value in the data source and setting that value from the rule.
     
    Know when to use calculated default values vs set a field's value
    The “Set a field’s value” action is best for values that only need to be set/copied once, or for values that are conditional. For values that need to update every time another field changes unconditionally, best to use a calculated default value. Good examples for rules:
    • Demo button that populates an entire form with sample data
    • Copying suggested values from a secondary data source that the users can edit afterward
    • Setting someone’s email address based on their name, but only if the email field is blank beforehand
     
    Got tips?
    If you've got your own best practices we'd love to hear them! Post a comment to share your insights with the whole community.
     
    - Ned
  • Microsoft InfoPath 2010

    Create a Rating Control using Picture Buttons

    • 3 Comments

    In this short video demo, Matt Bielich from the InfoPath test team shows how you can add a rating control to your InfoPath 2010 forms using picture buttons.

    Get Microsoft Silverlight
  • Microsoft InfoPath 2010

    Using Relink When Moving a SharePoint Form Library to a New Site

    • 8 Comments

    When InfoPath form files are saved to a SharePoint Form Library, SharePoint creates hard-coded references to the form template in the team site where the forms are being saved.  If the SharePoint Form Library is moved to a new location, the references in the InfoPath form files will continue to point to the old location, even after they've been moved into the new Form Library. In order to fix up the references in the form files to point to the new form template location, you need to perform a Relink operation.

    Important   Before performing the Relink operation, make sure that the Windows SharePoint Services server you are working with has been updated with Windows SharePoint Services Service Pack 1. This service pack release fixes a bug that can cause data corruption when performing a Relink operation.

    Note   You cannot relink a form if the all data in the form has been digitally signed (the form template has been configured for signing by using the Enable digital signatures for the entire form option, or by using the Enable digital signatures for specific data in the form option with the Set of signable data specified using an XPath expression of "/"). This is because when a form has been signed using this configuration the link to the form template is treated as part of the form data, and relinking would invalidate the signature. You can relink a form that has only part of the data signed (the form template has been configured for signing by using the Enable digital signatures for specific data in the form option with the Set of signable data specified as a subset of the data). For more information on using digital signatures, see Digitally Signing Data in InfoPath 2003.

    Here are the steps for performing a Relink operation:

    1. Open the new form library.
    2. Click Modify Columns and Settings to the left of the view.
    3. Under General Settings, click Relink forms to this form library.
    4. In the view presented, select all of the forms that you want to relink.
    5. Click the Relink button.

    The references in all of the forms you selected in step 4 will now point to the current form library location.

    Note   It is also possible to update the references in the form files using the Processing Instruction Update Tool provided with the InfoPath 2003 Software Development Kit (SDK); however in most cases the using the procedure above is simpler.

  • Microsoft InfoPath 2010

    InfoPath & Outlook 2003 Calendar Sync

    • 2 Comments

    If the title of this post interested you, check out Microsoft’s Sample solution for Recruiting, which has sample code for scenarios involving interview management. Just follow these links:

    http://www.gotdotnet.com/Workspaces/Workspace.aspx?id=162697e2-c63c-42e4-adae-a64b73e9b0a6

    http://www.microsoft.com/office/solutions/accelerators/recruiting/default.mspx

    The full source code is available for download at the first link above. Among other things, it has an InfoPath solution which:

    • Enables automatic scheduling (and creating) of appointments by looking up Exchange’s free busy information
    • Does processing of appointment accept/reject messages
      Presents the free busy information in the same way Outlook does, all in the InfoPath view!
    • Configurable scheduling window with built-in constraints such as “lunch”, “last” and “optional”
    • Smart algorithm for picking meeting times based on the number of interviewers – blending brute force with a Monte Carlo/heuristics-based mechanism.

    Cool stuff!

  • Microsoft InfoPath 2010

    Cool Forms! Weather Forecast Form

    • 8 Comments

    This week’s cool form displays your local weather forecast by using a REST Web Service data connection to pull in weather information from an online weather service. There are two views to the form, one minimal and one extended. The form contains linked picture controls that use rules to concatenate the Web service data and generate a URL pointing to images on the weather site. By hosting this form inside the InfoPath form Web part, you can display the latest weather forecast information on your SharePoint portal pages.

    Minimal View:

    weather_minimal

     

     

     

    Extended View:

    weather_extended 

    For more information about using REST Web Service data connections with InfoPath forms, see our earlier blog post http://blogs.msdn.com/infopath/archive/2010/02/11/add-a-dynamic-map-to-a-contact-form-using-rest-web-services.aspx.

    If you have a “cool” form that you would like to share with us, please send an e-mail with the following details to coolform@microsoft.com -

    • Attach 1 or 2 screenshots of your form
    • Provide a brief description of the form
    • You may also attach the XSN file (optional)

    The most popular submissions will be featured on our blog in future posts.

    Check out other Cool Forms here.

  • 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

    Browser Forms with Spell Check

    • 4 Comments
    With InfoPath Forms Services, you can take powerful InfoPath forms, and allow users to fill them out by using a browser. This enables your forms to reach more customers than ever before. Many Office users have been enjoying the convenience of spell check in Word and InfoPath. To enable this valuable feature for browser forms, we recommend pointing your customers to an Internet Explorer extension called ieSpell. It will check the spelling in your document, just like you would expect it to; you even get to store your personal word list or (clever!) point ieSpell to a Microsoft Office dictionary.
     
    After filling out a form, hit the ieSpell button and it pops up a dialog, similar to the Microsoft Office spell check. If you want to know the meaning of the word, the thesaurus is just a click away.
     
     
    Installing the program is quick and easy. Download from here (free for non-commercial use). When you're done, you will see a new button in the IE toolbar, as well as a new Tools menu item.
     
     
    If you are interested to learn more about ieSpell and other browser extensions, take a look at this article from the Internet Explorer team blog.
    Pradeep Rasam
    Program Manager
  • Microsoft InfoPath 2010

    Cool Forms! Feature Request Form

    • 0 Comments

    This week’s cool form is a feature request issue tracking list used by the Visio team. It’s divided into two main sections, the separate status section allows readers to jump directly to the information they care most about. It uses picture buttons to allow selection between ‘Office 14’ and ‘Office 15’ and to show which one is currently selected.  This form also dynamically generates the proper direct link to the bug database based on the bug ID that is entered.

    Feature Request Form

    If you have a “cool” form that you would like to share with us, please send an e-mail with the following details to coolform@microsoft.com -

    • Attach 1 or 2 screenshots of your form
    • Provide a brief description of the form
    • You may also attach the XSN file (optional)

    The most popular submissions will be featured on our blog in future posts.

    Check out other Cool Forms here.

Page 5 of 12 (298 items) «34567»