June 2005 - Posts - Greg Collins
in

InfoPath Dev

This Blog

Syndication

Greg Collins

June 2005 - Posts

  • Switch Views During the OnLoad Event

    InfoPath provides the SwitchView method to allow you to programmatically switch views from within your code. But SwitchView is a method of the View object, which does not exist until after the OnLoad event has completed. Any attempt, therefore, to use the SwitchView method in the OnLoad event handler will fail.

    The appropriate method to switch views during the OnLoad event is to set the default view. The default view is the view that will be displayed when the form first loads. Add the following code to the OnLoad event handler to set the default view:

    BLOCKED SCRIPT
    XDocument.ViewInfos("My View Name").IsDefault = true;

    C#:
    thisXDocument.ViewInfos["My View Name"].IsDefault = true;

    This code only works in the OnLoad event handler. Attempts to set the default view elsewhere will not accomplish anything—not even result in a failure.

    An alternative to setting the default view in the OnLoad event handler is to switch views using the open rules. This performs the same function, yet requires no code.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Lock the Format Painter for Repeated Usage

    The Format Painter, located on the Standard toolbar, is a very useful tool for applying established formatting from one item to another. It avoids the potentially lengthy process of applying a complex combination of formatting styles by use of the menus, task panes, etc. It does, however, have its limitations: It does not apply formatting such as borders, padding and margins, and it can be very tedious to use as it only applies the source formatting to a single destination before you need to reselect the source formatting.

    Although there is nothing that can be done about the borders, padding and margins, there are two rather obscure approaches that allow you to continue to apply the source formatting without the need to reselect it after each application.

    Before addressing each approach it should be noted that switching views will cause the format painter to reset, or lose it settings. It is therefore impossible to paint a format across views. To work around this, you can copy the formatted text from the source view and paste it into the destination view, use the format painter, and then delete the copied source text.


    APPROACH 1 – LOCK THE FORMAT PAINTER ON

    The first approach is to lock the Format Painter on. You do this by first clicking on or selecting the source of the formatting, and then double-clicking the toolbar button. The Format Painter will remain in this locked position until you unlock it. This allows you to continue to apply the source formatting to multiple destinations without needing to reselect it. To unlock the Format Painter press Escape, click the toolbar button again, activate another toolbar button or menu item, or start typing.


    APPROACH 2 – USE KEYBOARD SHORTCUTS

    The second approach is to use the keyboard shortcuts. The source formatting you select using either the Format Painter toolbar button or the keyboard shortcut is stored until you change it. To use the keyboard shortcuts, first click on or select the source of the formatting, and then press Ctrl+Shift+C to copy it. You can continue applying the source formatting by clicking on or selecting the destination, and then pressing Ctrl+Shift+V.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Change the Checked and Cleared Values of a Check Box

    Changing the checked and cleared values of a check box bound to a field in the main data source is easily accomplished using the built-in UI on the Data tab of the Check Box Properties dialog box. Changing the checked and cleared values of a check box bound to a field in a secondary data source requires manually modifying the view .xsl file.

    When you add a data connection to an .xml file, InfoPath makes no attempt to decipher data types for each field and attribute but simply assigns everything the string data type. Although this can be inconvenient, it can be fixed.

    When you insert a Check Box into the view for a field with the string data type, whether from the main data source or a secondary data source, InfoPath will always use yes for the checked value and no for the cleared value (as shown in Figure 1).


    Figure 1. For string data type fields, InfoPath uses yes for the checked value and no for the cleared value.

    When you insert a Check Box into the view for a field with the Boolean data type, whether from the main data source or a secondary data source, InfoPath will always use true for the checked value and false for the cleared value (as shown in Figure 2).


    Figure 2. For Boolean data type fields, InfoPath uses true for the checked value and false for the cleared value.

    Figures 1 and 2 illustrate that a check box bound to a field in a secondary data source does not provide the ability to change the checked and cleared values, as these options are grayed out. If your form is expecting these values to be something other than yes/no or true/false, you will need to modify the view .xsl file to change these values.

    In this task we will create a form that includes a secondary data source with two fields intended to hold Boolean values, for which InfoPath will create a schema using the string data type. We will modify the view .xsl file to use 1 and 0 as the checked and cleared values of the first check box, and use Present and Absent as the checked and cleared values of the second check box. Let's start by creating the secondary data source.

    Create the secondary data source:

    Copy the following code into a text editor, and then save the file as Booleans.xml. This file will be used as a secondary data source in our form.

    <?xml version="1.0" encoding="UTF-8"?>
    <Booleans>
        <ItemAvailable/>
        <StudentAttendance/>
    </Booleans>

    Add the secondary data source to a form:

    1. Design a new blank form.
    2. Choose Data Connections from the Tools menu, and then click Add.
    3. In the Data Connection Wizard, select Receive Data, and then click Next.
    4. Select XML Document, and then click Next.
    5. Click Browse, locate and select the Booleans.xml file, click Open, and then click Next.
    6. Click Finish, click Yes, and then click Close.

    Insert the two check boxes into the view:

    1. Open the Data Source task pane.
    2. Select the Booleans secondary data source.
    3. Right-click ItemsAvailable, click Check Box, and then press Enter.
    4. Right-click StudentAttendance, and then click Check Box.

    Modify the view .xsl file:

    1. Choose Extract Form Files from the File menu.
    2. Select a location to save your extracted form files to, and then click OK.
    3. Close InfoPath to release the lock it places on your form files.
    4. Using a text editor, open your view .xsl file.

    Change the checked and cleared values for the first check box:

    1. Search for the text xd:offValue="no" to locate the input element that represents your first Check Box control.
    2. Make the following changes to the first input element:

    xd:offValue="no" xd:onValue="yes"

    to:

    xd:offValue="0" xd:onValue="1"

    1. Search for the text &quot;yes, and then make the following change:

    ItemAvailable=&quot;yes&quot;

    to:

    ItemAvailable=&quot;1&quot;

    Change the checked and cleared values for the second check box:

    1. Search for the text xd:offValue="no" to locate the input element that represents your second Check Box control.
    2. Make the following changes to the second input element:

    xd:offValue="no" xd:onValue="yes"

    to:

    xd:offValue="Absent" xd:onValue="Present"

    1. Search for the text &quot;yes, and then make the following change:

    StudentAttendance=&quot;yes&quot;

    to:

    StudentAttendance=&quot;Present&quot;

    Review your changes:

    1. Save the view .xsl file, and then close the text editor.
    2. Reopen your form template by right-clicking the manifest.xsf file and choosing Design.

    Now when examine the Check Box Properties dialog boxes for the two check boxes, you will find your altered checked and cleared values, as shown in Figure 3. Provided that you do not delete the modified check box and insert a new one, the updated values will be persisted even through a rebinding.


    Figure 3. The checked and cleared values have been manually modified.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Remove a Form Template From the Cache

    The first time a form template is launched, InfoPath places it into its form template cache. On each subsequently launch, InfoPath will first check to see whether the template is already in the cache. This is very beneficial for forms that are only available online. If you are working with an online form, and you go offline, the cached form template is still available.

    While you are still designing your form template you will be testing the work you do. If you preview your form template from the designer, all of the latest changes will be made available. But previewing is not always an appropriate method to test your form. If you save the form template and then launch it from another method, the latest changes might not be made available if the form template is already in the cache. To remedy this you will need to remove the form template from the cache.

    Removing a form template from the cache is accomplished differently based on whether it was installed from a .msi file. You are not allowed to remove an installed form template in the same way you can a normal form template. Installed form templates must be uninstalled.

    In this task, we will learn how to remove a normal, and an installed form template from the InfoPath cache. This will force InfoPath to reload the form template from the source the next time it is launched, thus making available any recent changes.

    Remove a normal form template from the InfoPath cache:

    1. Close any open instance of the form template you want to remove.
    2. Launch InfoPath, or if InfoPath is already open choose Fill Out A Form from the File menu.
    3. In the Fill Out A Form dialog box, select the form that you want to have removed from the cache.

    If you do not find the form listed, select the All Forms category, and then look again.

    1. Click Remove This Form in the Form Tasks.

    Remove an installed form template from the InfoPath cache:

    1. Shut down InfoPath.
    2. Open the Windows Control Panel.
    3. Launch Add Or Remove Programs.
    4. Locate and select the installed form template, and then click Remove.
    5. Click Yes if asked whether you are sure you want to remove the form template from your computer.

    That's it. You have successfully removed a form from the cache. For a normal form template, you only need to launch it again and it will be added back to the cache with the latest changes. An installed form must be reinstalled from an updated .msi file.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Make Hyperlinks Visually Interactive

    The InfoPath designer only allows you to change the color of a hyperlink. It does not allow you to remove the underline text decoration, nor does it allow you to create a separate color for when the mouse pointer is hovering over the hyperlink or for when the user tabs to the hyperlink. These designer limitations can be overcome by manually modifying the view .xsl file.

    In this task we will make hyperlinks visually interactive by adding a custom internal style sheet to your view .xsl file. Let's start by designing a new blank form.

    Add a Hyperlink control to the view:

    1. Open the Controls task pane.
    2. Insert a Hyperlink into the view.
    3. In the Insert Hyperlink dialog box, type http://www.InfoPathDev.com into the Link To Address text box, and then click OK.

    Try it:

    1. Preview your form.
    2. Hover over the hyperlink, tab to it, and click on it to see how it responds.
    3. Close the preview.

    As you can see, InfoPath does not display hyperlinks differently for any of the mouse and keyboard activity we tried. Now let's enhance the behavior.

    Manually add a custom internal style sheet to the view:

    1. Choose Extract Form Files from the File menu.
    2. Select a location to save your extracted form files to, and then click OK.
    3. Close InfoPath to release the lock it places on your form files.
    4. Using a text editor, open the view .xsl file.
    5. Add the following code just below the last style element:

    <style title="myCustomHyperlinks" type="text/css">
        A { COLOR: orange; TEXT-DECORATION: none }
        A:visited { COLOR: red; } <!-- This pseudo class has no effect in the editor -->
        A:active { COLOR: blue; TEXT-DECORATION: underline }
        A:hover { COLOR: green; TEXT-DECORATION: underline }
    </style>

    If you have already made any color changes to the hyperlinks in the designer, you will need to manually remove the font elements immediately around your hyperlink text to allow your new styles to take effect.

    1. Save your view .xsl file, and then close the text editor.

    Try it:

    1. Reopen your form template by right-clicking the manifest.xsf file and choosing Design.
    2. Preview your form.
    3. Hover over the hyperlink, tab to it, and click on it to see the changes.

    The styles specified in the active pseudo class appear when the user tabs to the hyperlink, while the style specified in the hover pseudo class appear when the user holds the mouse pointer over the hyperlink. The ordering of the pseudo classes is important. If active is listed after hover, the user will not have any mouseover effects for the active hyperlink. If this is the effect you desire, make the appropriate change in order.

    The visited pseudo class appears to work in the designer, but the InfoPath editor does not keep track of which links were visited; therefore the user will never see this style applied.

    For more information about custom style sheets, refer to Add a Custom Style Sheet to a View.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Continue a Numbered List

    When creating numbered lists in InfoPath, you might need to have the numbers of a second list continue where the first list left off. In Microsoft Word you can right-click the numbers of the second list and choose Continue Numbering. You cannot do this in InfoPath. Though not as convenient, InfoPath does provide a couple ways to do this.

    In this task we will examine two approaches to continuing a numbered list: start numbering at a specific number and use line breaks. Each approach has an advantages and disadvantages. Let's start with a new blank form.


    APPROACH 1 – START NUMBERING AT A SPECIFIC NUMBER

    InfoPath provides an obscure feature at the bottom of the Bullets And Numbering task pane that allows you to specify a starting number for a numbered list. The advantages of this approach are that the content placed between the two lists can appear as a normal paragraph—meaning that it will not be indented, the content is not actually part of the list, and there are no restrictions to the content that can be used. The disadvantage is that the number chosen to start the second list is fixed and must be updated when items are added to or removed from the first list.

    Create a ten item numbered list:

    1. Click Numbering on the Formatting Toolbar to create a numbered list.
    2. Add ten random items to the numbered list.

    Specify the starting number for a list:

    1. Click on the end of list item five to set the insertion point.
    2. Press Enter, and then press Backspace to separate the lists.
    3. Add some random non-list content.
    4. Click on the start of the second list to set the insertion point.
    5. Choose Bullets and Numbering from the Format menu.
    6. In the Start Numbering At spin box at the bottom of the Bullets and Numbering task pane, specify the number 6.

    One interesting thing to note is that although you can choose between Arabic, Roman, or Alphabetic number formatting, the Start Numbering At spin box always displays Arabic numbers.


    APPROACH 2 – USE LINE BREAKS

    Another obscure feature—part of rich text editing—is that you can press Shift+Enter on a list item to create a line break rather pressing Enter, which will create a new list item. The advantage of this approach is that the list is never actually broken. There is, therefore, no issue with continuing numbers becoming out of sync. The disadvantages are that line breaks are indented to left-align with the list item, the non-list content is actually part of the list item, and layout tables are forced onto a new list item. There are also certain formatting features that may not work as expected (or at all) in this approach.

    Create a ten item numbered list:

    1. Click Numbering on the Formatting Toolbar to create a numbered list.
    2. Add ten random items to the numbered list.

    Insert line breaks:

    1. Click on the end of list item five to set the insertion point.
    2. Press Shift+Enter to create a line break.
    3. Add some random non-list content, making sure to use Shift+Enter instead of Enter to start each new line.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Create a "Same As" Check Box

    When creating a purchase order you need to gather the user's billing information as well as their shipping information. The user might want their order shipped to their billing address, in which case their shipping address is the same as their billing address. At other times they might want their order shipped elsewhere, as in the case of purchasing a gift for someone else.

    In this task we will create the shipping/billing section of a purchase order form and focus on how to reliably allow the user to specify whether to use their billing information as the shipping information. Let's start by designing a new blank form.

    Create the schema:

    1. Open the Data Source task pane.
    2. Double-click myFields and rename it to Order.
    3. Add a Group named Billing.
    4. Add a Group named Shipping.
    5. Select the Billing group, and then add eight Text Fields named Name, Street1, Street2, City, State, PostalCode, Phone, and Email.
    6. Right-click the Name text field, choose Reference, select the Shipping group, and then click OK.
    7. Perform the previous step for each of the seven remaining text fields in the Billing group, preserving their order.
    8. Select the Shipping group and then add a True/False Attribute Field named sameAsBilling with its default value set to False.

    We have just created a schema that will allow us to gather billing and shipping information for a purchase order. Figure 1 shows the completed schema in the Data Source task pane. The shipping information contains the same fields as the billing information with the addition of a Boolean value to allow the user to indicate whether they want their order shipped to their billing address or somewhere different. Now let's create the view.


    Figure 1. The purchase order data source

    Design the view layout:

    1. Choose Font from the Format menu.
    2. In the Font task pane, select Heading 2.
    3. At the top of the view, type PURCHASE ORDER, and then press Enter.
    4. Insert a 1 x 2 Layout Table into the view.
    5. In the left cell of the layout, type Billing Information:, and then press Enter.
    6. In the Data Source task pane, right-click the Billing group, choose Controls In Layout Table, and then drag the right edge of the inserted billing layout table to use the remaining space of the containing layout table cell.
    7. In the right cell of the layout table, type Shipping Information ():, and then press Enter.
    8. In the Data Source task pane, right-click the Shipping group, choose Controls In Layout Table, and then drag the right edge of the inserted shipping layout table to use the remaining space of the containing layout table cell.
    9. Select the text Same As Billing and its associated check box, drag-and-drop it between the parentheses on the line above, and then remove the extra line breaks that were inserted during the drop.
    10. Select the two empty cells remaining from where we just moved the text and check box, and then press Delete.

    The view is now laid out, and the results can be seen in Figure 2. At this point the user can fill in their billing and shipping information, but the Same As Billing check box is non-functional. Let's add two rules on the check box such that when it is selected, the billing fields are copied to the shipping fields, and when the check box is cleared, the shipping fields are cleared.


    Figure 2. The completed purchase order layout

    Add a rule to the check box to copy the billing fields:

    1. Double-click the Same As Billing check box.
    2. In the Check Box Properties dialog box, click Rules, and then click Add.
    3. Name the rule Copy Billing Fields, and then click Set Condition.
    4. In the Condition dialog box, select True in the third drop-down list, as shown in Figure 3, and then click OK.
    5. Click Add Action.
    6. In the Action dialog box, select Set A Field's Value from the Action drop-down list.
    7. Click the Select XPath button to the right of the Field text box, select Shipping/Name, and then click OK.
    8. Click the Insert Formula button to the right of the Value text box, click Insert Field Or Group, select the Billing/Name field, and then click OK three times.
    9. Add seven more actions to this rule to copy the remaining fields from the Billing group to the Shipping group.
    10. Click OK to complete this rule.


    Figure 3. Setting the rule condition

    Add a rule to the check box to clear the shipping fields:

    1. In the Rules dialog box, click Add.
    2. Name the rule Clear Shipping Fields, and then click Set Condition.
    3. In the Condition dialog box, select False in the third drop-down list, and then click OK.
    4. Click Add Action.
    5. In the Action dialog box, select Set A Field's Value from the Action drop-down list.
    6. Click the Select XPath button to the right of the Field text box, select Shipping/Name, and then click OK twice, leaving the Value text box blank.
    7. Add seven more actions to this rule to clear the remaining fields in the Shipping group.
    8. Click OK three times to close all open dialog boxes.

    Previewing the form at this point, you will find that any values you enter into the billing fields are copied to the shipping fields when you select the Same As Billing check box, and that each of the shipping fields are cleared when you clear the check box. But there are a couple of issues that need to be resolved.

    First, when the Same As Billing check box is selected, you can still change the values in the shipping fields, effectively making the check box inaccurate. Second, when the check box is selected, any changes you make to the billing fields are not reflected in the shipping fields. Let's make the changes necessary to correct these issues.

    Prevent the user from changing the shipping fields:

    1. Double-click the Name field in the shipping column.
    2. On the Display tab of the Text Box Properties dialog box, click Conditional Formatting, and then click Add.
    3. Select sameAsBilling in the first condition drop-down list, and then select True in the third condition drop-down list.
    4. Select the Read-Only formatting check box, and then click OK three times to close all open dialog boxes.
    5. Add this same conditional formatting to each of the seven remaining shipping fields in the view.

    Ensure that the shipping fields reflect changes made to the billing fields:

    1. Double-click the Name field in the billing column.
    2. On the Data tab of the Text Box Properties dialog box, click Rules, and then click Add.
    3. Name the rule Copy Changes to Shipping Name, and then click Set Condition.
    4. Select Select A Field Or Group in the first condition drop-down list.
    5. In the Select A Field Or Group dialog box, select the Shipping/sameAsBilling field, and then click OK.
    6. Select True in the third condition drop-down list, and then click OK.
    7. Click Add Action.
    8. In the Action dialog box, select Set A Field's Value from the Action drop-down list.
    9. Click the Select XPath button to the right of the Field text box, select Shipping/Name, and then click OK.
    10. Click the Insert Formula button to the right of the Value text box, click Insert Field Or Group, select the Billing/Name field, and then click OK six times to close all open dialog boxes.
    11. Add similar rules, naming them appropriately, to each of the seven remaining billing fields in the view.

    With these last two changes our billing/shipping section is complete. The user can enter separate billing and shipping information or choose to have their shipping information be the same as their billing information by selecting the Same As Billing check box. If the user selects the latter option, the shipping data will accurately reflect the most current billing information, even if changes are made to the billing information.

    Try it:

    Preview the form and test your new billing/shipping section with and without the Same As Billing check box selected. The completed form is shown in Figure 4.


    Figure 4. The completed purchase order billing/shipping section

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Remove Text Highlighting

    When using the text highlighter on the contents of a rich text field, or on the contents of a view in the designer, InfoPath insert a font element around the text being highlighted, setting the background color to the selected highlight color.

    The following code block shows the XHTML of two paragraphs in a rich text field. The first paragraph has no highlight, while the second one has a yellow highlight.

    <div xmlns="http://www.w3.org/1999/xhtml">This text has no highlight.</div>
    <div xmlns="http://www.w3.org/1999/xhtml"><font style='BACKGROUND-COLOR: #ffff00'>This text has a yellow highlight.</font></div>

    Adding a highlight is as simple as selecting text and then choosing the highlight color; but removing the highlight is not as obvious. Microsoft Word has a very definite choice of None among its highlight colors (as shown in Figure 1) while InfoPath does not.


    Figure 1. InfoPath (left) provides more highlight colors than Word (right), but does not provide the option for ‘None’.

    Although not obvious, InfoPath also provides a None choice: the white highlight color. If you select text with a highlight color and then choose the white highlight color, InfoPath will remove the font element from the XHTML contents of the rich text field. Our previous code block would now look like this:

    <div xmlns="http://www.w3.org/1999/xhtml">This text has no highlight.</div>
    <div xmlns="http://www.w3.org/1999/xhtml">This text has a yellow highlight.</div>

    But there is a catch. The white highlight color will only remove the highlight when the entire highlighted section is selected, otherwise it will insert a font element to set a white background color. For example, if instead of selecting the entire second paragraph and setting the highlight color to white, we only select a portion of the highlighted text (whether that be at the start, middle, or end of the paragraph), the resulting XHTML will look something like this:

    <div xmlns="http://www.w3.org/1999/xhtml">This text has no highlight.</div>
    <div xmlns="http://www.w3.org/1999/xhtml"><font style='BACKGROUND-COLOR: #ffff00'>This <font style='BACKGROUND-COLOR: #ffffff'>text has</font> a yellow highlight.</font></div> </my:field1>

    The results of this behavior would be more obvious if the background color of the control or view were set to something other than the default white color.

    So how do you completely remove the highlight color from a portion of the highlighted text rather than change it to white? The solution is to use another less obvious option, which is the keyboard shortcut for removing text formatting. To use the keyboard shortcut, select the desired text, and then press Ctrl+Space to remove the formatting. Although this works, if you had other formatting besides just the highlight color, you might end up with unexpected results. This approach is fully described in Quickly Remove Text Formatting.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Disable a Button Until All Required Fields are Filled In

    You might have a button in your form—such as a submit button—that you want to prevent the user from being able to click until all required form fields are filled in. This can be done using conditional formatting. The complexity of the conditional formatting depends on your form.

    In this task we will create a simple form with a submit button. We will add conditional formatting to disable the button until all required form fields are filled in. Let’s start by designing a new blank form.

    Create the schema:

    1. Open the Data Source task pane.
    2. Add a Text Field named Name, which cannot be blank.
    3. Add two Text Fields named Address, and Phone.
    4. Add a Text Field named Email, which cannot be blank.
    5. Add a Rich Text Field named Comments.

    Add custom data validation to require that the rich text field cannot be blank:

    Since we cannot specify in the data source that the rich text field cannot be blank, we must do this manually with custom data validation. Rich text fields work differently than plain text fields—you cannot simply check whether a rich text field “is blank” because this will not always produce accurate results.

    1. In the Data Source task pane, double-click Comments.
    2. On the Validation And Event Handlers tab of the Field Or Group Properties dialog box, click Add.
    3. Select The Expression from the first drop-down list, and then type the following expression:

    not(.//node())

    1. Type Cannot be blank for the ScreenTip (as shown in Figure 1), and then click OK twice.


    Figure 1. Custom validation requiring that a rich text field cannot be blank.

    Design the view:

    1. Right-click myFields, and then choose Controls In Layout Table.
    2. From the Controls task pane, insert a Button into the view.
    3. Double-click the button.
    4. On the General tab of the Button Properties dialog box, change the label to Submit, and then change the ID to btnSubmit.
    5. Click Rules, and then click Add.
    6. Name the rule Submit, and then click Add Action.
    7. Select Show A Dialog Box Message from the Action drop-down list.
    8. Type Form Submitted for the message, and then click OK three times.

    Add conditional formatting to disable the button:

    1. On the Display tab of the Button Properties dialog box, click Conditional Formatting, and then click Add.
    2. Select Name from the first drop-down list, select Is Blank from the second drop-down list, click And, and then select Or in place of And.
    3. Select Email from the first drop-down list, select Is Blank from the second drop-down list, click And, and then select Or in place of And.
    4. Select The Expression from the first drop-down list, and then type the following expression:

    not(my:Comments//node())

    1. Select the Disable This Control check box (as shown in Figure 2), and then click OK three times.


    Figure 2. The conditions required to disable the button.

    Try it:

    When you first preview the form you will find that the Name, Email and Comments fields are all marked with a red asterisks, indicating that they are required fields; you will also find that the Submit button is disabled. When you fill in the required fields the Submit button becomes enabled, allowing you to then submit the form. Figure 3 shows the form before and after the required fields are filled in.


    Figure 3. The submit button is disabled until all required fields are filled in.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Prevent Field Validation From Occurring OnLoad

    The OnValidate event fires for each field in your main DOM before the OnLoad event is fired. This allows you to write validation code to add custom errors to the Errors collection for invalid fields before the user ever sees the view. This might be necessary when you are unsure of the source of the XML and for numerous other reasons. Although very useful, you might have validation event handlers that you do not want processed at this point. It is possible to prevent these validation event handlers from being processed.

    Because the View object does not exist until the first OnSwitchView event, which occurs after the OnLoad event, you can use this to detect whether your validation event handler is being called before the OnLoad event. To skip this initial OnValidate event, add the following code to the beginning of your validation event handler:

    if(null == eventObj.XDocument.View)
        return;  // Ignore OnValidate before the OnLoad event.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Keep the Form Aligned with the Background Picture When Printing

    If you design your form to strictly layout over a background picture, you will find that when you print or use print preview your form no longer aligns with the background picture. Using a grid background picture, Figure 1 shows the extent of the layout variation between the editing and printing.


    Figure 1. Forms align to a background picture differently for printing.

    InfoPath requires a 21px left margin in the view to allow for the widget icon that appears when you hover over repeating controls. This margin is not required for printing. Each view .xsl file contains an internal style sheet (shown in the following code block) which uses the @media screen at-rule to specify that the media for the contained set of styles applies to computer display screens only—not for other media types such as print.

    <style controlStyle='controlStyle'>
        @media screen {
            BODY { margin-left:21px; background-position:21px 0px; }
        }
        . . .
    </style>

    The style contained in the media at-rule specifies that the background picture be offset the same 21px as the body contents. When you print, both the body margin and the background position will revert to their default values because the media at-rule no longer applies. One problem is that InfoPath places an inline style on the body element, which overrides this at-rule, as seen here:

    <body style='BACKGROUND-POSITION: left top; BACKGROUND-REPEAT: no-repeat' background='backgroundPicture.jpg'>

    When the background-repeat property has a value of no-repeat, the background-position property is added to the inline style. This property overrides the at-rule style. By setting your background picture to tile horizontally, vertically, or both, as shown in Figure 2, the background-position property is removed, thus allowing the at-rule style to be applied. But even tiling your background picture, there will be a misalignment between editing and printing because the at-rule specifies a value of zero for the top background position.


    Figure 2. Setting the background picture to tile horizontally and vertically.

    There are two approaches to matching the alignment of the form contents to the background picture between editing and printing. Each approach will do the trick, but will result in different alignment as can be seen in Figure 3 and Figure 4. The first approach is to modify the standard InfoPath internal style sheets and the inline style on the body element. This approach has some drawbacks—it works well for when you are finished modifying your form template, but you chance losing your modifications if you make them before you are finished. The first approach also explains why this problem exists. The second approach is simpler and will survive modifications to the form template. Let’s review the two approaches.


    APPROACH 1 – MODIFY THE STANDARD INTERNAL STYLE SHEETS AND INLINE STYLES

    You can manually remove the background-position property from the inline style on the body element, but even this will not fix all of the issues. The first problem is that if you ever make changes in the View Properties dialog box, InfoPath will update the inline style, thus reverting your changes. The second problem is that this only fixes the left position. Referring to Figure 1, you can see that both the left and top positions are different between editing and printing. This can be corrected by adjusting the top position in the at-rule style as follows:

    <style controlStyle='controlStyle'>
        @media screen {
            BODY { margin-left:21px; background-position:21px 15px; }
        }
        . . .
    </style>

    If you now load your form in the editor the background picture will have the same alignment as it does when you print. But there’s still a problem; in the designer the top position did not get adjusted. One more addition to a different internal style will fix that. Paste a copy of the at-rule into the style block with the tableEditor attribute. Your three modifications to the view .xsl file are as follows:

    <style controlStyle='controlStyle'>
        @media screen {
            BODY { margin-left:21px;background-position:21px 15px; }
        }
        . . .
    </style>


    <style tableEditor="TableStyleRulesID">
        @media screen {
            BODY { margin-left:21px; background-position:21px 15px; }
        }
        . . .
    </style>


    <body style='BACKGROUND-REPEAT: no-repeat' background='backgroundPicture.jpg'>

    With these three modifications in place, your background picture will align the same in the designer, the editor, and for print. The results can be seen in Figure 3 below.


    Figure 3. Following Approach 1, the form aligns to the upper left of the background picture.

    This is all great and good so long as you do not make any changes to your form template that would require you to make these changes again. InfoPath often regenerates the standard internal style sheets as well as the inline style on the body element. Constantly battling the designer to keep your modifications is not a pleasant task, and there is an alternative.


    APPROACH 2 – ADD A CUSTOM INTERNAL STYLE FOR PRINT MEDIA

    The alternative is to leave the standard internal style sheets and the inline style alone and to create your own internal style sheet which will adjust the margins of the body contents over the background picture for print. You do this by adding the following the following code just below the last style element in the view .xsl file:

    <style title="BackgroundPicturePosition">
        @media Print {
            BODY{ margin-left:21px; margin-top:15px; }
        }
    </style>

    By adding your own at-rule for print media, you overcome the InfoPath designer roundtripping issue. The results are shown in Figure 4. Either way will work, but the latter alternative is safer and less work. For more details on internal style sheets, refer to Add a Custom Style Sheet to a View.


    Figure 4. Following Approach 2, the form aligns to the background picture with margins.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Display Rich Content in an Expression Box

    When you bind an Expression Box to a Rich Text field you might be surprised to find that all of the formatting and rich content are gone, and that you are left with a single-line string of plain text. Getting the rich content to display requires only a small manual modification to the view .xsl file.

    In this task we will create an Expression Box bound to a Rich Text field that displays with rich content. We will also look into an issue you might experience as a result of this modification and what can be done about it. Let's start by designing a new blank form.

    Create a Rich Text Box and bind an Expression Box to it:

    1. Open the Controls task pane.
    2. Insert a Rich Text Box into the view.
    3. In the Data Source task pane, right-click field1, and then choose Expression Box.
    4. Resize the Expression Box to be the same width as the Rich Text Box above it.

    Try it:

    1. Preview the form.
    2. Add some rich content to the Rich Text field, and then click outside of the field to bind the content.


    Figure 1. An Expression Box bound to a Rich Text field does not display rich content.

    As you can see in Figure 1, the rich content is not displayed in the Expression Box. This is because InfoPath does not consider the data type of the bound field when creating an Expression Box but instead always uses the xsl:value-of element in the XSL. The xsl:value-of element converts the results of its selection to a string by calling the string() function. To allow for rich content, we must change to use the xsl:copy-of element.

    Modify the view .xsl file to allow the Expression Box to display rich content:

    1. Choose Extract Form Files from the File menu.
    2. Select a location to save your extracted form files to, and then click OK.
    3. Close InfoPath to release the lock it places on your form files.
    4. Using a text editor, open your view .xsl file.
    5. Search for the text ExpressionBox to locate the span element that represents your Expression Box control.
    6. Change the following line from:

    <xsl:value-of select="my:field1"/>

    to:

    <xsl:copy-of select="my:field1/node()"/>

    1. Save the view .xsl file, and then close the text editor.
    2. Reopen your form template by right-clicking the manifest.xsf file and choosing Design.

    Try it:

    1. Preview the form.
    2. Add some rich content to the Rich Text field, and then click outside of the field to bind the content.


    Figure 2. The modified XSL allows the Expression Box to display rich content.

    Figure 2 shows that the modification we just made to the XSL allows the Expression Box to display rich content. Something you might have noticed was that if you hover over the contents of the Expression Box, a blue border appears around the field. This is uncharacteristic of an expression box, and usually an undesirable effect.

    There is an issue in InfoPath that causes this blue border to appear when hovering over an Expression Box modified to display rich content when a Rich Text Box bound to the same field is in the same view. To prevent this blue border from appearing on hover, you must ensure that the Expression Box does not appear in the same view as a Rich Text Box. If the two controls are in separate views, this hover effect will not occur.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Using XPath's 'preceding-sibling' Axis Correctly

    The XPath axis, preceding-sibling, can be a bit confusing to use. It doesn't work the way one would expect at all. In fact, it is quite backward from what one would expect.

    To me it made sense that if I wanted the sibling just before where I was currently at I would use an XPath like this:

    preceding-sibling::NodeName[last()]

    That made sense to me... but it didn't work. After some digging around I discovered that preceding-sibling works in a reverse direction. If I were to diagram it out, using an 'X' to represent the current location, it would look like this:

    preceding-sibling

     current() 

    following-sibling

    last()

    ...

    2

    1

    X

    1

    2

    ...

    last()

    Thus, using last(), I would really end up with the first one in the list (as we humans think). So if I want access to the immediate preceding-sibling, I would instead use an XPath like this:

    preceding-sibling::NodeName[1]

    This would correctly provide me with the immediate preceding-sibling (this technique is demonstrated in the InfoPathDev example form: Reordering Table Rows). I could increase the number used if I wanted to walk further back the chain.

    So in essence, as you go forward (following-sibling) or backward (preceding-sibling), the number of steps you take is based off of where you currently are, with last() being the furthest possible away from where you are, in the direction you are going.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Prevent Button Borders from Appearing Bold

    You might encounter a situation where a button in your view appears to have a bold border, as shown in Figure 1. Traditionally in the Microsoft Windows operating system, a bold border designates a default button—meaning it is the one that is activated by default when you press Enter assuming you haven't changed the focus to another button. This is not the case here, as InfoPath does not utilize default buttons.

    The issue stems from a design flaw in the rendering of the Windows XP style button control, and does not occur in the Windows Classic style. When the width of the Windows XP style button reaches 192px, the border renders differently, making it appear bold. This is also true if the height of the button reaches 87px.


    Figure 1. Button borders appear bold when at widths greater than 191px.

    If this is visual artifact is an issue for you then you need to do what it takes to keep the width of the button below 192px, and the height of the button below 87px. This might mean modifying the button label text, or manually sizing the button.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

  • Display Inline Pictures From a Rich Text Field on a Web Page

    To display your InfoPath form data in a Web page, you can write XSL to translate your form into HTML. With a little knowledge of XSL this is a straightforward task. To display the contents of a rich text field you must use xsl:copy-of instead of xsl:value-of. This allows the XHTML content to be displayed in the Web page.

    But you will quickly discover that this works for everything in a rich text field except pictures. This is because InfoPath stores pictures using base64 encoding, and then embeds the resulting string directly into the XML content—specifically into the xd:inline attribute of the img element. The XHTML for a picture in a rich text field will look something like the following:

    <img style='WIDTH: 100px; HEIGHT: 122px' tabIndex='-1' src='msoinline/a0d1eb893d744127' xmlns:xd='http://schemas.microsoft.com/office/infopath/2003' xd:inline='/9j/4AAQSkZJRgABAQEASABIAAD...'/>

    The src attribute tells InfoPath that the encoded picture is stored inline in the xd:inline attribute. But Internet Explorer does not understand the contents of the src attribute and ignores the xd:inline attribute, thus failing to display the picture. Because xsl:copy-of performs a single operation copy of the contents of the node, there is no way to handle the pictures independently. For this we must write our own "copy-of" code. Displaying inline pictures in your Web page requires extra work, but the results are worth it.

    In this task we will create a simple InfoPath form with a rich text field that contains inline pictures, and then display the decoded pictures in a Web page. We will use XSL to transform our XML form into HTML, and then use an ASPX page to make the base64 encoded pictures displayable in the Web page. This task requires that you have available to you an installation of Internet Information Services (IIS), version 6.0 or later, and will assume that you have it installed on your local machine. Let's start by designing a new blank form, and then we will create the several support files needed to complete this task.


    THE FORM TEMPLATE

    Create the test form template:

    1. Open the Controls task pane.
    2. Insert a Rich Text Box into the view.
    3. Double-click the rich text field.
    4. In the Rich Text Box Properties dialog box, change the field name to RichTextField, and then click OK.
    5. Save the form template as InlinePictures2Html.xsn, and then close InfoPath.


    THE MYFORM.XML FILE

    Create the test form:

    1. Launch the InlinePictures2Html.xsn form.
    2. Insert several pictures into the rich text field.
    3. Save the form as C:\Inetpub\wwwroot\form\myForm.xml, and then close InfoPath.


    THE DEFAULT.ASPX FILE

    The default.aspx file is the landing page for the Web user. This page initiates the XSL transformation our InfoPath form into an HTML Web page. This is the first of three key files required to display inline pictures from a rich text field in a Web page. Copy the following code into a text editor, and then save the file as C:\Inetpub\wwwroot\form\default.aspx. Note that this is the same folder that you saved the myForm.xml file to.

    <%@ Page Language="C#" %>
    <%@ Import Namespace="System.Xml" %>
    <%@ Import Namespace="System.Xml.Xsl" %>

    <!-- Source code developed by Greg Collins -->

    <script language="C#" runat="server">
    void Page_Load(Object sender, EventArgs e)
    {
        // Create an XSL argument to provide the absolute URL to the XML file being transformed.
        // This argument will be availabe as an xsl:param named URL.
        XsltArgumentList oArgs = new XsltArgumentList();
        string sPath = Request.Path.ToString();
        sPath = sPath.Substring(0, sPath.LastIndexOf("/")+1) + "myForm.xml";
        oArgs.AddParam("URL", "", sPath);
        xmlFile.TransformArgumentList = oArgs;
    }
    </script>

    <asp:Xml id="xmlFile" runat="server" DocumentSource="myForm.xml" TransformSource="/transform.xsl" />

    Let's examine what the default.aspx file is actually doing. If we were not attempting to decode inline pictures from a rich text field the entire script block would be unnecessary. The purpose of the script block is to get the path from the root folder to the XML file to be transformed, and then pass it as a parameter to the XSL. We are using code to identify this path but you could just as easily hardcode it.

    Because Request.Path actually returns the path to the default.aspx file, we must remove the filename portion of the path and replace it with the filename of the XML file to be transformed. We could use Server.MapPath("myForm.xml") here, but this might pose a security issue due to the physical directory structure it reveals; instead we will save that for the decodePicture.aspx file. The modified path becomes the value of a parameter named URL, which is passed to and used in the transform.xsl file.

    Values from two attribute on the asp:Xml element must be referenced in the script block: the id attribute and the DocumentSource attribute.  The value of the id attribute is the name of the object whose TransformArgumentList property is being set at the end of the script block. If these two do not match an error will occur. The value of the DocumentSource attribute is the name of the XML file to be transformed and is appended to the path after removing the name of this ASPX file. If these two do not match you will receive undesirable results in your Web page.


    THE TRANSFORM.XSL FILE

    The transform.xsl file is what transforms our InfoPath form into the HTML that will be displayed in a Web page. This is the second of three key files required to display inline pictures from a rich text field in a Web page. It employs custom "copy-of" functionality to process img elements independently of other XHTML elements within the rich text field. This separation is important in order to specify that the source of the picture will be supplied by an ASPX page.

    You must ensure that any namespaces used in your form are also included in the namespace declarations on the xsl:stylesheet element. If you fail to include a namespace the XSL will not be processed.

    Copy the following code into a text editor, and then save the file as C:\Inetpub\wwwroot\transform.xsl. This file is saved to the root folder so that it can be easily accessed from anywhere in your Web site.

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:cs="C#" xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2004-11-03T18:01:22">
    <xsl:strip-space elements="*" />
    <xsl:output method="html" indent="no" />

    <!-- Source code developed by Greg Collins -->

    <!-- Parameter specifying the absolute URL of the XML file being transformed -->
    <xsl:param name="URL"/>

    <xsl:template match="/">
        <h1>Rich Text Pictures Displayed in a Web Page:</h1>
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="my:RichTextField">
        <xsl:apply-templates />
    </xsl:template>

    <!-- Template for every element except pictures -->
    <xsl:template match="my:RichTextField//*[name(.) != 'img']">
        <xsl:element name="{name(.)}">
            <xsl:for-each select="@*">
                <xsl:attribute name="{name(.)}"><xsl:value-of select="."/></xsl:attribute>
            </xsl:for-each>
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>

    <!-- Template specifically for pictures -->
    <xsl:template match="my:RichTextField//*[name(.) = 'img']">
        <xsl:element name="img">

            <!-- Copy every attribute except for 'src' and 'xd:inline' -->
            <xsl:for-each select="@*[name(.) != 'src' and name(.) != 'xd:inline']">
                <xsl:attribute name="{name(.)}"><xsl:value-of select="."/></xsl:attribute>
            </xsl:for-each>

            <!-- Generate the 'src' attribute to decode the base64 picture -->
            <xsl:attribute name="src">/decodePicture.aspx?u=<xsl:value-of select="$URL"/>&amp;n=<xsl:value-of select="count(preceding::*[name(.) = 'img'])"/></xsl:attribute>
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>

    </xsl:stylesheet>

    Let's examine what the transform.xsl file is actually doing. The xsl:param element receives its value from the parameter set by the default.aspx page that initiated the transformation. This value is the path from the root folder to the XML file being transformed. This parameter is essential because it allows the code in decodePicture.aspx to load that XML file and decode each of its base64 encoded pictures.

    The script block is used to create an index of the inline pictures. Each picture is assigned an incrementally larger number starting from zero. The code in decodePicture.aspx uses these numbers to know which picture is being requested.

    Because our sample form is so simplistic, the main template only places a header on the page. The real work is done when the template for the rich text field is processed. If pictures were not saved inline, you would simply be able to use an xsl:copy-of element here and be done with it; but because we are dealing with inline pictures, we must write custom "copy-of" functionality. This requires two templates: one for the img element, and one for everything else.

    The first of our custom "copy-of" templates matches the XPath my:RichTextField//*[name(.) != 'img'], or in other words, any element inside the rich text field that is not named img. In this template we copy the element, giving it the same name, copy each of its attributes, and then continue applying templates.

    The second of our custom "copy-of" templates matches the XPath my:RichTextField//*[name(.) = 'img'], or in other words, any element inside the rich text field, as long as it is named img. This template is very similar to the previous one, creating an element of the same name, and then copying the attributes; only this time we specifically do not copy  two of the attributes: src and xd:inline. The src attribute will be constructed later and the xd:inline attribute will be left for the decodePicture.aspx page to work with. It is this latter attribute that actually contains the base64 encoded picture.

    The reason we wrote custom "copy-of" functionality was to set up the src attribute of the img element so that it will call the decodePicture.aspx page to request the decoded picture. To do this we provide two parameters representing the URL to the XML file we are currently transforming and an index to the picture we are currently working on. The resulting img element, transformed for our HTML Web page, will look something like the following:

    <img style='WIDTH: 100px; HEIGHT: 122px' tabIndex='-1' src='/decodePicture.aspx?u=/myForm.xml&amp;n=0'>

    The contents of this transform.xsl file are the barebones requirements to ensure that your rich text pictures will be displayed. Beyond this you would write your XSL to transform the remainder of your InfoPath form into HTML for your Web page.


    THE DECODEPICTURE.ASPX FILE

    The decodePicture.aspx file is where we decode the base64 encoded inline pictures. This is the third of three key files required to display inline pictures from a rich text field in a Web page. This file gets called by the Web browser when it encounters the src attribute of the img element that we created as part of the XSL transformation.

    Copy the following code into a text editor, and then save the file as C:\Inetpub\wwwroot\decodePicture.aspx. This file is saved to the root folder so that it can be easily accessed from anywhere in your Web site.

    <%@ Page Language="C#" Debug="true" %>
    <%@ Import Namespace="System.IO" %>
    <%@ Import Namespace="System.Xml" %>
    <%@ Import Namespace="System.Collections" %>

    <!-- Source code developed by Greg Collins -->

    <script language="C#" runat="server">
    void Page_Load(Object sender, EventArgs e)   
    {
        try
        {
            // Get the parameters.
            string sXmlFile = Request.QueryString["u"];
            int nPictureNumber = Convert.ToInt32(Request.QueryString["n"]) * 2;
            if(null == sXmlFile || 0 > nPictureNumber)
                return;
       
            // Get the server path to the XML file.
            sXmlFile = Server.MapPath(sXmlFile);
       
            // Attempt to get the decoded pictures from the cache.
            ArrayList arrPicture = (ArrayList)Cache[sXmlFile];
            System.Drawing.Image oPicture;
       
            // If not already there, decode the pictures and add them to the cache.
            if(null == arrPicture)
            {
                // Load the XML file that was transformed.
                XmlDocument oXml = new XmlDocument();
                oXml.Load(sXmlFile);
           
                // Add the appropriate namespaces so the selection will work.
                XmlNamespaceManager oNsm = new XmlNamespaceManager(oXml.NameTable);
                oNsm.AddNamespace("rt", "http://www.w3.org/1999/xhtml");
                oNsm.AddNamespace("xd", "http://schemas.microsoft.com/office/infopath/2003");
           
                // Get the full list of xd:inline attributes on img elements.
                XmlNodeList oPictures = oXml.SelectNodes("//rt:img/@xd:inline", oNsm);
                arrPicture = new ArrayList();
                for(int i = 0; i < oPictures.Count; i++)
                {
                    // Convert each base64 encoded string into an actual picture.
                    string sBase64Picture = oPictures.Item(i).Value;
                    byte[] bPicture = Convert.FromBase64String(sBase64Picture);
                    MemoryStream oMemStr = new MemoryStream();
                    oMemStr.Write(bPicture, 0, bPicture.Length);
                    oPicture = System.Drawing.Image.FromStream(oMemStr);
                   
                    // Add each decoded picture and it's format to the array.
                    arrPicture.Add(oPicture);
                    arrPicture.Add(sBase64Picture.Substring(0, 4));
                }
           
                // Store the picture array in the Application Cache.
                Cache.Insert(sXmlFile, arrPicture, new CacheDependency(sXmlFile));
            }
       
            // Ignore request if the picture number excedes what's in the array.
            if(arrPicture.Count <= nPictureNumber)
                return;
       
            // Obtain the specified picture and format.
            oPicture = (System.Drawing.Image)arrPicture[nPictureNumber];
            string sPictureFormat = (string)arrPicture[nPictureNumber+1];
       
            // Send the decoded picture back to the Web page to be displayed.
            // R0lG = Uppercase R + Number Zero + Lowercase L + Uppercase G
            if("R0lG" == sPictureFormat)
                oPicture.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
            else
                oPicture.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
        catch(Exception ex)
        {
            // If anything goes wrong do not display an error, just return with no picture.
            return;
        }
    }
    </script>

    Let's examine what the decodePicture.aspx file is actually doing. Two query string parameters are retrieved from the src attribute of the img element produced by our custom XSL transform: the path from the root folder to the XML file containing the inline pictures, and the index of the particular picture to decode. The index is immediately multiplied by two because the array created to store the decoded pictures also stores a sibling piece of information that identifies the picture format. If either parameter is not present, we just return, which results in a broken picture in the Web page.

    The sXmlFile variable is immediately converted to the absolute server path using Server.MapPath(sXmlFile). This variable is used to load the XML file, and is also used as the name of the object we store in the cache.

    The first thing we do is discover whether this particular XML file has already been parsed and stored in the cache; if so we use the cached version. Caching our pictures significantly improves performance because we do not need to load the XML file each time a decoded picture is requested. If not already in the cache, we must take the time decode the pictures, and then add them to the cache.

    To do this we must load the XML file, and then add the namespaces required to be able to reach the pictures in the rich text fields. Two namespaces in particular need to be added: the first is for the rich text field, and the second is for the xd:inline attribute of the img elements. After we've added the namespaces, we get the list base64 encoded pictures, and then one-by-one, decode them.

    Each decoded picture is stored in an array along with the four characters at the beginning of the base64 encoded picture. These four characters identify the picture format, whether it is GIF or JPEG. We must determine the picture format because JPEG pictures displayed in GIF format do not look as good, and GIF pictures displayed in JPEG format do not allow for animated pictures. The four characters representing a GIF picture are R0lG. The four characters representing a JPEG picture are /9j/.

    Although InfoPath supports more picture formats than GIF and JPEG, for our purposes, these are the only formats that exist. This is because all the other picture formats display correctly in one of these two formats.

    With all of these files in place you will be able to correctly display inline pictures from a rich text field in your Web pages. You can test this by launching your Web browser and navigating to http://localhost/form/default.aspx.

    One thing to note is that decoded inline pictures will not render as quickly as those loaded from actual picture files stored on a server; but this is a minor issue compared to the convenience of being able to display the complete contents of your rich text fields in a Web page, including the inline pictures.

    ©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.

More Posts Next page »
Copyright © 2003-2019 Qdabra Software. All rights reserved.
View our Terms of Use.