Greg Collins Sign in | Join | Help in Greg Collins Tutorials (Entire Site) InfoPath Dev InfoPath Dev is dedicated to bringing you the information and tools you need to be successful in your Microsoft Office InfoPath development projects. Home Blogs Forums Photos Downloads This Blog Home About Syndication RSS Atom Comments RSS Recent Posts Swap the AD Alias and Name Fields in Place Create a Split Public/Private Form Display a Save As Dialog Box Highlight the Active Field Use the SharePoint '[Me]' Filter with a Promoted Property Tags Active Server ADWS Alias ASPX Background Borders Bugs Bullets and Numbering Buttons Cache Cascading Check Boxes Code concat() Conditional Formatting Conditional Visibility copy-of count Cross-Domain current Data Validation Debugging DisplayName domEventHandlers E-Mail Error Errors Events Expression Boxes Extract Form Files File Extension File Types Filters Focus Footer Formatting Forms Full Trust GetNamedNodeProperty Greg Collins Header Help Hyperlinks Internet Explorer Lists Managed Code Me Namespaces New NewFromSolution NewFromSolutionWithData number Numbered Lists OnAfterChange OnClick OnContextChange OnLoad OnSwitchView Operating System Option Buttons Outlook Picture Pictures position preceding preceding-sibling Preserve Code Blocks Printing processing-instructions Promoted Property References RegForm Repeating Sections Repeating Tables Rich Text Boxes Roles Rules Save As Schema Script Secondary Data Sources Sections Security SetNamedNodeProperty SharePoint SQL Style Sheets Submit Task Panes Template Text Boxes Tile Views Visual Studio Warning Windows Explorer Workarounds xdExtension xdXDocument XPath Archives October 2009 (1) April 2009 (1) March 2006 (1) November 2005 (1) September 2005 (1) July 2005 (4) June 2005 (24) March 2005 (2) January 2005 (1) November 2004 (1) October 2004 (1) September 2004 (6) August 2004 (5) July 2004 (20) June 2004 (5) Greg Collins Remove a Print Header or Footer To add a header or footer to your InfoPath form printout, do the following:In the Views task pane, double-click the view for which you want to add a header or footer.In the View Properties dialog box, select the Print Settings tab.Click Header, or click Footer.Construct the header or footer the way you want and then click OK.Click OK to exit the View Properties dialog box.That was the easy part. The hard—rather confusing—part is trying to remove the header or footer you just created. Try it:In the Views task pane, double-click the view for which you want to remove a header or footer.In the View Properties dialog box, select the Print Settings tab.Click Header, or click Footer.Press CTRL+A to select the entire text, then press DELETE.Click OK.Now click header, or click footer, again—the text was not deleted! What happened?You can do this over and over and nothing will change. I'm sure this was just an oversight on the part of the developers. A bug that was not caught. So what can be done?The answer is simple—instead of pressing DELETE, press SPACE, then click OK. Now when you go back to look, the header or footer will have been successfully deleted. InfoPath recognized that you had unprintable text and so it defaulted back to removing the header or footer.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 09 2004, 10:56 AM by Greg Collins with 1 comment(s) Filed under: Printing, Header, Footer Identify the Current Table Row If you are trying to identify the current table row so that you can make modifications to other field in that row, the safest thing to do is to make those modifications using code. This will be the fastest (performance-wise) solution. You can see how this is done by playing with my example form: Populating Table Row After Selection (Code).But if you absolutely do not want to touch code, you can do this with Rules and a node to hold the current row position. This RowPosition node should be located in a secondary data source so as to not dilute your main DOM. The concept is simple.Let's assume you have an XML structure, using the "my" namespace, that is organized like the following: People Person Name First Last Address Phone EmailLet's also assume that we have a secondary data source named Support that is organized like the following: Support RowPositionYou would create a Rule on the desired node, in this example, we'll use Phone. The Rule will set the value of the RowPosition node, in the secondary data source, to the XPath function count(XPath_To_Repeating_Row_Node) + 1. In this case the XPath would be ../preceding-sibling::my:Person. Why my:Person? Because that is the actual "row" of the table. That is the repeating node. So if we were to place the Rule on my:First, we would have to modify the function to include an additional axis specifier (i.e. another "../"). The resulting XPath would then be ../../preceding-sibling::my:Person.This will work even when filters or conditional formatting are used to hide certain rows.Once you have the row position saved, you can use it to get direct access to your row for making updates to other fields. You do this by modifying the XPath of each Rule that updates another field on the row. In the case of our example XML structure above, you would locate my:People/my:Person/... in the XPath and modify it to include the specified row. It would now look like: my:People/my:Person[number(xdXDocument:GetDOM("Support")/Support/RowPosition)]/... .You must specify the XPath number() function or this technique will not work.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 08 2004, 11:54 AM by Greg Collins with no comments Filed under: XPath, Rules, Repeating Tables, preceding-sibling, count, number, current Display Multiple Fields in a Drop-Down List Box While developing your InfoPath form, you might need to have a drop-down list box display more information from more than one field. This is actually quite simple by manually modifying your view .xsl file. In this task we will demonstrate the changes necessary to display multiple fields in a single drop-down list box.APPROACH 1:The first approach is the easiest. It involves manually modifying the view .xsl file and using the XPath concat() function to display the combined values of multiple fields in the drop-down list box.If, for example, you have XSL that looks something like this: <option> <xsl:attribute name="value"> <xsl:value-of select="my:EmployeeId"/> </xsl:attribute> <xsl:if test="$val=my:EmployeeId"> <xsl:attribute name="selected">selected</xsl:attribute> </xsl:if> <xsl:value-of select="my:LastName"/></option> Modify the XSL (see the changes highlighted in red) to look something like this: <option> <xsl:attribute name="value"> <xsl:value-of select="my:EmployeeId"/> </xsl:attribute> <xsl:if test="$val=my:EmployeeId"> <xsl:attribute name="selected">selected</xsl:attribute> </xsl:if> <xsl:value-of select="concat(my:LastName, ', ', my:FirstName, ' (', my:EmployeeId, ')')"/></option> These modifications will roundtrip in the designer. This means that when you load your form template in the designer, make changes to it, and then save it, these modifications will not be lost.APPROACH 2:The second, and potentially more robust, approach is to populate the drop-down list box via code. This technique is demonstrated in my example form: Fully Editable Drop-Down List Box. By using code, you can completely customize your drop-down list box.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 08 2004, 02:33 PM by Greg Collins with 2 comment(s) Filed under: Lists, concat() Avoid an Endless Loop During Event Bubbling Event bubbling means that when an event, such as the OnAfterChange event, happens on a particular data node in an XML tree, that event is passed up to the parent node, and then the grandparent node, and so on, all the way back to the root node. Thus the event "bubbles" up the tree.Consider an XML structure like the following: Group1 Node1 Node2 Attribute1 Attribute2 Node3If all you wanted was to know whether Attribute1 had changed, you would place an OnAfterChange event handler on Attribute1. But this event would also then be passed to Node2, and then to Group1.If however you wanted to know whether any node under Group1 had changed, you could place an OnAfterChange event handler on Group1. This is very powerful. Now you can write a single event handler to manage value changes for all of Group1's sub nodes rather than write individual event handlers on each node.But how do you know which node the event occurred on to be able to properly respond to it? The InfoPath event object has a couple of properties that help you resolve this. They are Site and Source. Site: The XML node that the event handler is attached to. Source: The XML node that caused the event.Thus if the OnAfterChange event handler were placed on Group1 and a change occurred to Attribute2, when the event handler was called, the Site property would be Group1, and the Source property would be Attribute2. You could use a switch statement on Source.nodeName to handle the event differently for each node under Group1.But with all this power comes the danger and responsibility. A serious problem can occur if you handle the event on Group1 and then as part of handling that event you make a change to one of its child nodes, let's say, Node3. The change made to Node3 will now set off another round of OnAfterChange events, which will then bubble up to Group1, causing another change in Node3, which will then bubble up, and so on. This is known as an endless loop or recursion.InfoPath catches endless loops--it will stop them after 16 calls to prevent the form from locking up. But that still doesn't solve your problem. You really don't want to ever get into an endless loop. So what can be done?If you know that your form users will never modify Node3, but that only your code will be modifying it as part of the event handler, you can use the Site property of the event object to filter out any events that originated from Node3. If the user will be making changes as well, then you can set a Boolean flag in your code, identifying that it was the code, and not the user that made the change. Then when the event bubbles up and the flag is set, you simply reset the flag and do not make the change to Node3 again.Using this technique you can effectively prevent endless loops, or recursion, during event bubbling. To see this technique demonstrated, take a look at my examples forms: Populating Table Row After Selection (Code), Fully Editable Drop-Down List Box and Accessing and Updating Repeating Table Row Cells.©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 07 2004, 08:04 PM by Greg Collins with no comments Filed under: Code, Events Using Rules to Update Fields in a Table Row While working today on my example form, Populating Table Row After Selection (Rules), I had an epiphany—a possible way of accomplishing this without resorting to manually editing the XSL or using code.The concept was to create a Support secondary data source with a RowPosition node who's soul purpose was to store the current row.In the table row existed a drop-down list box and a series of other fields. When the selection changed in the drop-down list box, the other fields should be updated with the correct values from a SQL database. Here's what I did:When the selection changed, I fired a series of rules to populate the table row fields with the corresponding SQL database fields, filtered on the selection made in the drop-down list box. This works great for a single table row, but not so good for multiple rows.By adding an initial rule which sets the value of the RowPosition node in the Support DOM with the value of the XPath function count(../preceding-sibling::my:RowNode) + 1, I now have a reference to the current table row.At this point I updated each of the other rules to make use of the RowPosition node. Here's a before and after of one particular rule with the difference highlighted:BEFORE:xdXDocument:GetDOM("Customers")/dfs:myFields/dfs:dataFields/d:Customers/@CompanyName[../@ContactName = xdXDocument:get-DOM()/my:myFields/my:Customers/my:Customer/@my:Name]AFTER:xdXDocument:GetDOM("Customers")/dfs:myFields/dfs:dataFields/d:Customers/@CompanyName[../@ContactName = xdXDocument:get-DOM()/my:myFields/my:Customers/my:Customer[xdXDocument:GetDOM("Support")/Support/RowPosition]/@my:Name]With the addition of storing the current row and the change to the XPath for setting the field values, I was sure it would work. But, alas, it didn't. It didn't take long to figure out why. My initial guess was correct. The RowPosition was being filled in as a string. By making one more adjustment, and forcing it to be a number, the solution worked beautifully! Here's the final working version:FINAL:xdXDocument:GetDOM("Customers")/dfs:myFields/dfs:dataFields/d:Customers/@CompanyName[../@ContactName = xdXDocument:get-DOM()/my:myFields/my:Customers/my:Customer[number(xdXDocument:GetDOM("Support")/Support/RowPosition)]/@my:Name]There are other issue to tackle too, such as having a drop-down list box in each row of a table can quickly become a huge performance hit. If you are using a Master-Detail table, you can move the drop-down list box into the Detail table. This will certainly help as you will then only have a single source for the list instead of one per row.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 06 2004, 04:28 PM by Greg Collins with no comments Filed under: Rules, Repeating Tables, Workarounds, Bugs Faulty Condition Expressions 2004-07-03I uncovered this bug today while trying to figure out why an InfoPathDev example form I've been preparing hasn't been working correctly. I've reported it to my Microsoft contacts, but it is unlikely that there will be any fix for this in SP1 before it ships. This bug has caused me grief for a long time, and I finally figured out why.I have a Rule on a control with a condition that I built using the InfoPath UI formula builder.The expression that InfoPath created for me was this:msxsl:string-compare(., count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1) > 0But the problem is that InfoPath is forcing the condition to be validated as a string compare. Because of this false positives and negatives are returned in certain circumstances. For example, the string comparison of "4" > "10" will return TRUE.The expression I was trying to get was the following:. > (count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1)With the hand-made adjustment to the expression I am now comparing actual values instead of strings. This gives me the correct result of FALSE for a value comparison of 4 > 10.By manually updating the rule condition, the change will stay intact until you open the rule condition using the InfoPath UI again. Then it reverts back to using msxml:string-compare(). If you click cancel, your manual update is retained, but if you click OK you will have to fix it again.I consider this a data loss situation, because A) InfoPath did not give me the intended results when I first created the condition, and B) any time I make a change to the condition, it reverts back.The problems are that A) I did not know up-front that InfoPath was creating a string comparison, B) it took a lot of time to debug the problem, C) when the condition is modified, I’ll likely not remember that I need to manually modify the expression until I find that the form isn't function properly, and D) whenever someone else makes a change, they may never figure it out!If I post an example that uses this technique, and others were playing around in the rules to see what I did, A) they would never see the correct condition I manually created because InfoPath will automatically convert the expression back to using msxml:string-compare(), and thus they'll never be able to figure out how I made it work, B) after they look at the condition, the form may no longer function as intended, and C) unless I document this well, they'll never be able to create the same condition expression that I did.2004-07-09The InfoPath team responded to me today. Their email sparked an idea for a possible workaround, which ultimately did work. I'll discuss that solution after reviewing their comments and the two recommendations they gave, both of which work. I'll explain why one of their recommendations is good in some circumstances, and not in others. I'll also explain why their other recommendation will always work, as will mine. A member of the InfoPath team took a stab in the dark and made the assumption that my current node (represented by the dot in the expression) was a string datatype. He was correct. Because of this InfoPath defaulted to a string-based comparison. This was why it kept adding the msxsl:string-compare() function. The first recommendation that the InfoPath team gave me was to changing the string datatype into a number datatype. For my example I was creating, this was the correct approach. Making this change, InfoPath recognized the Integer datatype and left out the string comparison. This change is great when you have control over the schema and it makes sense (as was my case) to use a number datatype for the field in question. There are many times when this will not be the case. So another fix is needed. The second recommendation that the InfoPath team gave me was to create my own comparison function. You can do this by writing a function in code that in this case checks if value A is greater than value B. In my particular case I would write a function called IsGreater() which accepts either two numeric values or two nodes. Then in the rules I would call into this function using xdExtension like this:xdExtension:IsGreater(., count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1)The function should return a boolean (true/false).This solution is great because you can do whatever you want in code. You can get as complex as needed, with the entire XDocument DOM at your disposal. But many people do not want to write code, and some people don't know how to. This is also a bit more complex for the as simple a task as I was trying to do.So now on to my solution. The idea I had while reading their replies to me was that if I just add an XPath function number() around the current node (represented by the dot), that this should be enough to keep InfoPath from being able to "resolve" the XPath into something it can understand, thus forcing it to leave it alone. This too worked—and is much simpler than writing your own function, though less robust. Thus the resulting expression looked like this:number(.) > count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1)So there you have it—three solutions to a troubling problem. The biggest problem now is just recognizing that your condition is being modified. The only way to do that is to edit the condition and then change the first drop-down list box in the Condition dialog box to be "The expression". This allows you to see the full XPath expression to see if it is what you are expecting it to be. It is different, one of these workarounds should do the trick!©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 03 2004, 08:23 AM by Greg Collins with 1 comment(s) Filed under: Conditional Formatting, Workarounds, Bugs How to Really Depress a Button! Status: Not fixed as of the InfoPath 2003 SP2 release. I uncovered this bug merely on 2004-07-03 and reported it to my Microsoft contacts.I discovered that you can get a button into a depressed state and have it stuck there until you release it with another click. It's really not a hard thing to do. And what's worse is then when the button is placed into this state it will not perform its assigned functionality because the click was never released. It is not until the click is released that the rules and code behind the button are processed.Here are the steps:Start with a new blank form.Insert a button into the view.Preview the form.Left-click the button, but don’t release.Right-click the button, and then release.Now release the left-click.Results: The button stays in a depressed state.Left-click the button.Results: The button returns to normal state.Close the preview.Add a rule to the button to show a dialog box message.Preview the form.Perform steps 4-6 above.Results: The rule did not fire.Left-click the button.Results: The rule fires.Close the preview.You can also use a UI.Alert() in place of the rule and the effect is the same. If you use both a rule and an Alert, the affect is the same, only when the button is finally released, the rule fires and then the code, as expected.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 03 2004, 06:32 AM by Greg Collins with no comments Filed under: Buttons, Workarounds, Bugs Min/Max Error Message Limitation I wrote to my Microsoft contact a while back to request that a future version of InfoPath make the repeating sections smart enough to realize that they have hit the specified min or max limit and then hide the appropriate widget for insert or remove.But while trying to discover a way to work around that, I noticed that the error message that pops up when a min or max condition is hit happens before, and instead of, the OnBeforeChange() event handler. This is bad because there is no way for the form developer to show their own error message. Instead you are stuck with the default cryptic error message that InfoPath supplies, namely:On insert:InfoPath cannot insert the section or row because of an error.Details:The attempted fragment operation cannot be completed because there is no valid insertion point for the fragment.On remove:The item cannot be removed.Details:Content for element '{http://schemas.microsoft.com/office/infopath/2003/myXSD/2004-07-01T23:47:14}group1' is incomplete according to the DTD/Schema.Another idea I had while playing with this, and recommended Microsoft implement in conjunction with the aforementioned idea is: Allow rules to separately control the insert and delete widgets and the menu items that appear.So for example, if you have a limit of 10 rows, but you only want the user to insert 3 a maimum of 3 rows under a certain condition, then you could set a rule that would disable the "Insert" feature until the condition was no longer valid. The same thing would work for removing rows.These would be very powerful and very useful.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 01 2004, 05:05 PM by Greg Collins with 1 comment(s) Filed under: Repeating Tables, Workarounds, Bugs, Repeating Sections, Errors Too Lazy to Switch Views STATUS: Fixed in InfoPath 2003 SP1DESCRIPTION:While working on a project for Microsoft, Patrick Halstead and I were using some complex Open Rules and were having trouble getting things to work right. So, under the pressure of a deadline, we decided to convert them to code in the OnLoad event handler. It was during this process that we uncovered this bug on 2004-03-19 and reported it to our Microsoft contacts. It was at that point unknown to Microsoft. After this our only solution was to convert back to using Open Rules, which, as complex as they were, we eventually resolved our issues and get them to work as desired.This bug is managed code specific, meaning it will not happen when using script. It is manifest when attempting to switch views in the OnLoad event handler, but only after the form has been cached locally.The first time you run the form, when it has not yet been cached, the view will switch as expected, but there-after, until you clear the form from the InfoPath form cache, the view will fail to switch.If you want see this happen, try this little experiment:Start Visual Studio.Create a new C# InfoPath Project, and name it ViewSwitchTest.In view 1, type the text View 1.Add a new view.In view 2, type the text View 2.In the Tools menu, select Programming | On Load Event. Enter the following line in the OnLoad event handler:thisXDocument.ViewInfos[1].IsDefault = true;Publish the form.Close InfoPath and Visual Studio.Open the form from the published location. It should open to view 2.Close InfoPath.Open the form again from the published location.BUG: The form opens to view 1.Clear the form out of the InfoPath cache.Open the form from the published location. It should open to view 2.Close InfoPath.Open the form again from the published location.BUG: The form opens to view 1.This can be a very bad bug if the need arises for it. So what can be done? The workaround is to use Open Rules to do your view switching. If you have complicated code to figure out which view to switch to, this may not be a viable alternative. But fortunately, most view switching during the OnLoad stage will be able to be accomplished in the Open Rules.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jul 01 2004, 04:37 PM by Greg Collins with no comments Filed under: OnLoad, Rules, Views, Workarounds, Bugs Help! Help is available for InfoPath as part of its installation. But one particular help file is, in my opinion, more useful than the others. Depending on your installation path it can be found at:C:\Program Files\Microsoft Office\OFFICE11\1033\MSE10.CHMWhy do I find this one so useful? Basically because it combines numerous help files into one. Here are the highlights:General Script Editor Information HTML in Microsoft Office Applications Working with Script and HTML in the Script Editor Customizing the Script Editor Managing Views and Windows Navigating, Searching, and Replacing InfoPath Developer's Reference Programming Concepts Developer Sample Forms Data Validation Events Structural Editing User InterfaceInfoPath Object Model Reference Collections Objects Properties Methods Events EnumerationsInfoPath XSF Reference Namespaces Types Groups Elements AttributesMSXML 5.0 SDK GUID and ProgID Information Dependencies in MSXML 5.0 XML Developer’s Guide DOM Developer’s Guide How Do I? Program with DOM in C/C++ Program with DOM in C/C++ Using Smart Pointer Class Wrappers Program with DOM in Visual Basic Program with DOM in JScriptDOM Reference XML DOM Objects/Interfaces XML DOM Properties XML DOM Methods XML DOM Events MSXML Helper APIsXML Digital Signature XML Digital Signature Developer's Guide XML Digital Signature Reference XML Digital Signature Interfaces XML Digital Signature Properties XML Digital Signature Methods XML Digital Signature Enumerated Types XML Digital Signature ElementsXML Schemas XML Schemas Overview XSD Schema Developer's Guide XML Schema Reference (XSD) XML Schema Elements XML Data Types Reference XML Schema Regular Expressions XML Schema Instance AttributesXDR Schema Developer's Guide XDR Schema Reference XDR Schema Elements XDR Schema Data Types ReferenceDTD Developer's Guide DTD ReferenceSOM Developer’s Guide SOM Reference XSLT Developer’s Guide XSLT Reference XSLT Elements XSLT Functions XSLT SyntaxXPath Developer’s Guide XPath Reference XPath Syntax XPath FunctionsSAX2 Developer’s Guide SAX2 ReferenceJScript JScript Language Reference JScript Tutorial Scripting Run-Time Library Reference FileSystemObject Object TutorialVBScript VBScript Language Reference VBScript Tutorial Scripting Run-Time Library Reference FileSystemObject Object TutorialDebugging Your Program in Office 10 Using the Debugger Inspecting Your ProgramDebugger Reference Visual Studio Getting Started Visual Studio ReferenceAs you can see there is a lot of information contained in this one help file! Make a shortcut to it somewhere where you can easily access it, whether it be using a keyboard shortcut, on your Start menu, or in your Quick Launch Toolbar.As you are developing your InfoPath forms, you will undoubtedly have a need for the information contained in one or more sections of this help file.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jun 30 2004, 08:34 PM by Greg Collins with no comments Filed under: Help Conditional Formatting Conundrum STATUS: Fixed in InfoPath 2003 SP2.SCOPE: SP1 Managed Code.DESCRIPTION:I uncovered this bug on 2004-03-08 and reported it to my Microsoft contacts. It was at that point unknown to Microsoft.This bug is managed code specific, meaning it will not happen when using script. It is manifest when populating an xdCombo box control from the main DOM or from a secondary data source. Initially everything will work fine. But once the view has been roundtripped in the designer, the conditional formatting will be removed from this control.WORKAROUNDS:Download and install service pack 2 of InfoPath 2003. Use a section around your drop-down list box, and place the conditional formatting on the section. Place the drop-down list box in a preserve block.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jun 29 2004, 06:12 PM by Greg Collins with no comments Filed under: Conditional Formatting, Workarounds, Bugs I Just Can't Keep the Rules! STATUS: Potentially fixed in InfoPath 2003 SP2.DESCRIPTION:I uncovered this bug on 2004-02-17 and reported it to my Microsoft contacts. It was at that point unknown to Microsoft.The rules that you defined actually remain in the manifest. The bug is that the xsf:domEventHandlers block goes *POOF*! One way for this to happen is if you open the manifest.xsf file in the Visual Studio editor after rules have been created. But there are others.Since the xsf:ruleSets block is still in the manifest, you could potentially attempt to establish stub rules for your controls and then manually reattach the domEventHandler to the correct ruleSet. But this may be more work than is worth the effort!Having said all this, it can still be be very annoying and very problematic to have your rules disappear. But there are a couple of things that I do, in the mean time, to avoid getting hit by this problem. You may find them useful too:Keep a back up copy of your manifest each time you change rules, just in case this does happen.Whenever you publish, always shut down InfoPath and either close your solution, or shut down Visual Studio.Any time you modify a solution file other than FormCode.xx within Visual Studio, always shut down InfoPath and either close your solution, or shut down Visual Studio.WORKAROUNDS:One workaround is to replace rules with code in the OnAfterChange event. But this may not always be preferred.I know it's a pain and inconvenient. And unfortunately you are one of the few of us who do the kinds of things that cause this. Just be patient and play by the rules I outlined above and you should be good to avoid it.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jun 29 2004, 05:57 PM by Greg Collins with no comments Filed under: Rules, Visual Studio, Managed Code, Workarounds, Bugs, ruleSets, domEventHandlers, OnAfterChange Order of Processing at Startup In InfoPath SP1, the order of processing at startup of a form is:User RolesOpen RulesOnLoad event handlerOnSwitchView event handlerThe User Roles are processed first so that when the Open Rules are evaluated that they can take into account the current role. The Open Rules can be used to change the default view. Then, after these have processed, the OnLoad event handler will take over. At this point the View object doesn't exist and any functionality requiring it will fail. As a result, you cannot switch views at this point, but can change the default view. Lastly the default view is created and the OnSwitchView event handler is called.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jun 26 2004, 01:16 PM by Greg Collins with 1 comment(s) Filed under: OnSwitchView, OnLoad, Roles, Rules, Launch The Case of the Missing PI DAY 1 (2004-06-24)I was just working with a set of forms where a non-managed code (i.e. JScript)—hereafter referred to as NMC—form launches a managed code (i.e. C#)—hereafter referred to as MC—form and passes in its data using the new InfoPath 2003 SP1 method NewFromSolutionWithData. I ran into a bug that I have Microsoft tracking down as I write.The problem occurs only when managed code is involved. It is related to the Preview version of InfoPath 2003 SP1. I expect it will be fixed in the release version of SP1.If I use the NewFromSolutionWithData method going from a NMC form to another NMC form, then the problem does not present itself. But if I go from a NMC form to a MC form, or if I got from a MC form to either a NMC or MC form, the problem appears.So what exactly is the problem? The problem is that 2 of the 3 processing-instructions (PIs) that appear at the top of an InfoPath .xml file get striped out, namely the PI and the PI.Missing the former PI is not a great loss, but without that latter PI, Windows does not know that the .xml file belongs to InfoPath and will therefore not attempt to open it using InfoPath. Also this will result in the .xml file not having the InfoPath icon to identify it.Luckily, most InfoPath developers will not encounter this situation. A possible work around, if you know you will get hit by this bug, is to use the OnLoad event handler to manually add the missing PIs back into the XML. I haven't tested this yet, but believe it will work.DAY 2 (2004-06-25) Having played around a little with the code, my initial hunch was correct, there is a workaround and it is using code. This will require that you establish some way of knowing that your form was opened using the NewFromSolutionWithData method, and then in the OnLoad event handler you can add the following code:C#IXMLDOMProcessingInstruction oXML = thisXDocument.DOM.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");IXMLDOMProcessingInstruction oPI = thisXDocument.DOM.createProcessingInstruction("mso-application", "progid=\"InfoPath.Document\"");thisXDocument.DOM.insertBefore((IXMLDOMNode)oPI, thisXDocument.DOM.firstChild);thisXDocument.DOM.insertBefore((IXMLDOMNode)oXML, thisXDocument.DOM.firstChild);JScriptvar oXML = XDocument.DOM.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");var oPI = XDocument.DOM.createProcessingInstruction("mso-application", "progid=\"InfoPath.Document\"");XDocument.DOM.insertBefore(oPI, XDocument.DOM.firstChild);XDocument.DOM.insertBefore(oXML, XDocument.DOM.firstChild);Thus, when the form is saved, the two missing PIs will be back in place and your form will be ready to roll.©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com. Posted Jun 24 2004, 05:57 PM by Greg Collins with no comments Filed under: OnLoad, Managed Code, Code, NewFromSolutionWithData, processing-instructions, Workarounds, Bugs, Script More Posts « Previous page Copyright © 2003-2019 Qdabra Software. All rights reserved.View our Terms of Use.
To add a header or footer to your InfoPath form printout, do the following:
That was the easy part. The hard—rather confusing—part is trying to remove the header or footer you just created. Try it:
You can do this over and over and nothing will change. I'm sure this was just an oversight on the part of the developers. A bug that was not caught. So what can be done?
The answer is simple—instead of pressing DELETE, press SPACE, then click OK. Now when you go back to look, the header or footer will have been successfully deleted. InfoPath recognized that you had unprintable text and so it defaulted back to removing the header or footer.
©2004 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.
If you are trying to identify the current table row so that you can make modifications to other field in that row, the safest thing to do is to make those modifications using code. This will be the fastest (performance-wise) solution. You can see how this is done by playing with my example form: Populating Table Row After Selection (Code).
But if you absolutely do not want to touch code, you can do this with Rules and a node to hold the current row position. This RowPosition node should be located in a secondary data source so as to not dilute your main DOM. The concept is simple.
Let's assume you have an XML structure, using the "my" namespace, that is organized like the following:
People Person Name First Last Address Phone Email
Let's also assume that we have a secondary data source named Support that is organized like the following:
Support RowPosition
You would create a Rule on the desired node, in this example, we'll use Phone. The Rule will set the value of the RowPosition node, in the secondary data source, to the XPath function count(XPath_To_Repeating_Row_Node) + 1. In this case the XPath would be ../preceding-sibling::my:Person. Why my:Person? Because that is the actual "row" of the table. That is the repeating node. So if we were to place the Rule on my:First, we would have to modify the function to include an additional axis specifier (i.e. another "../"). The resulting XPath would then be ../../preceding-sibling::my:Person.
This will work even when filters or conditional formatting are used to hide certain rows.
Once you have the row position saved, you can use it to get direct access to your row for making updates to other fields. You do this by modifying the XPath of each Rule that updates another field on the row. In the case of our example XML structure above, you would locate my:People/my:Person/... in the XPath and modify it to include the specified row. It would now look like: my:People/my:Person[number(xdXDocument:GetDOM("Support")/Support/RowPosition)]/... .
You must specify the XPath number() function or this technique will not work.
While developing your InfoPath form, you might need to have a drop-down list box display more information from more than one field. This is actually quite simple by manually modifying your view .xsl file. In this task we will demonstrate the changes necessary to display multiple fields in a single drop-down list box.
APPROACH 1:
The first approach is the easiest. It involves manually modifying the view .xsl file and using the XPath concat() function to display the combined values of multiple fields in the drop-down list box.
If, for example, you have XSL that looks something like this:
<option> <xsl:attribute name="value"> <xsl:value-of select="my:EmployeeId"/> </xsl:attribute> <xsl:if test="$val=my:EmployeeId"> <xsl:attribute name="selected">selected</xsl:attribute> </xsl:if> <xsl:value-of select="my:LastName"/></option>
Modify the XSL (see the changes highlighted in red) to look something like this:
<option> <xsl:attribute name="value"> <xsl:value-of select="my:EmployeeId"/> </xsl:attribute> <xsl:if test="$val=my:EmployeeId"> <xsl:attribute name="selected">selected</xsl:attribute> </xsl:if> <xsl:value-of select="concat(my:LastName, ', ', my:FirstName, ' (', my:EmployeeId, ')')"/></option>
These modifications will roundtrip in the designer. This means that when you load your form template in the designer, make changes to it, and then save it, these modifications will not be lost.
APPROACH 2:
The second, and potentially more robust, approach is to populate the drop-down list box via code. This technique is demonstrated in my example form: Fully Editable Drop-Down List Box. By using code, you can completely customize your drop-down list box.
Event bubbling means that when an event, such as the OnAfterChange event, happens on a particular data node in an XML tree, that event is passed up to the parent node, and then the grandparent node, and so on, all the way back to the root node. Thus the event "bubbles" up the tree.
Consider an XML structure like the following:
Group1 Node1 Node2 Attribute1 Attribute2 Node3
If all you wanted was to know whether Attribute1 had changed, you would place an OnAfterChange event handler on Attribute1. But this event would also then be passed to Node2, and then to Group1.
If however you wanted to know whether any node under Group1 had changed, you could place an OnAfterChange event handler on Group1. This is very powerful. Now you can write a single event handler to manage value changes for all of Group1's sub nodes rather than write individual event handlers on each node.
But how do you know which node the event occurred on to be able to properly respond to it? The InfoPath event object has a couple of properties that help you resolve this. They are Site and Source.
Site: The XML node that the event handler is attached to. Source: The XML node that caused the event.
Thus if the OnAfterChange event handler were placed on Group1 and a change occurred to Attribute2, when the event handler was called, the Site property would be Group1, and the Source property would be Attribute2. You could use a switch statement on Source.nodeName to handle the event differently for each node under Group1.
But with all this power comes the danger and responsibility. A serious problem can occur if you handle the event on Group1 and then as part of handling that event you make a change to one of its child nodes, let's say, Node3. The change made to Node3 will now set off another round of OnAfterChange events, which will then bubble up to Group1, causing another change in Node3, which will then bubble up, and so on. This is known as an endless loop or recursion.
InfoPath catches endless loops--it will stop them after 16 calls to prevent the form from locking up. But that still doesn't solve your problem. You really don't want to ever get into an endless loop. So what can be done?
If you know that your form users will never modify Node3, but that only your code will be modifying it as part of the event handler, you can use the Site property of the event object to filter out any events that originated from Node3. If the user will be making changes as well, then you can set a Boolean flag in your code, identifying that it was the code, and not the user that made the change. Then when the event bubbles up and the flag is set, you simply reset the flag and do not make the change to Node3 again.
Using this technique you can effectively prevent endless loops, or recursion, during event bubbling. To see this technique demonstrated, take a look at my examples forms: Populating Table Row After Selection (Code), Fully Editable Drop-Down List Box and Accessing and Updating Repeating Table Row Cells.
©2005 Greg Collins. All rights reserved. Licensed to Autonomy Systems, LLC for display on InfoPathDev.com.
While working today on my example form, Populating Table Row After Selection (Rules), I had an epiphany—a possible way of accomplishing this without resorting to manually editing the XSL or using code.
The concept was to create a Support secondary data source with a RowPosition node who's soul purpose was to store the current row.
In the table row existed a drop-down list box and a series of other fields. When the selection changed in the drop-down list box, the other fields should be updated with the correct values from a SQL database. Here's what I did:
When the selection changed, I fired a series of rules to populate the table row fields with the corresponding SQL database fields, filtered on the selection made in the drop-down list box. This works great for a single table row, but not so good for multiple rows.
By adding an initial rule which sets the value of the RowPosition node in the Support DOM with the value of the XPath function count(../preceding-sibling::my:RowNode) + 1, I now have a reference to the current table row.
At this point I updated each of the other rules to make use of the RowPosition node. Here's a before and after of one particular rule with the difference highlighted:
BEFORE:
xdXDocument:GetDOM("Customers")/dfs:myFields/dfs:dataFields/d:Customers/@CompanyName[../@ContactName = xdXDocument:get-DOM()/my:myFields/my:Customers/my:Customer/@my:Name]
AFTER:
xdXDocument:GetDOM("Customers")/dfs:myFields/dfs:dataFields/d:Customers/@CompanyName[../@ContactName = xdXDocument:get-DOM()/my:myFields/my:Customers/my:Customer[xdXDocument:GetDOM("Support")/Support/RowPosition]/@my:Name]
With the addition of storing the current row and the change to the XPath for setting the field values, I was sure it would work. But, alas, it didn't. It didn't take long to figure out why. My initial guess was correct. The RowPosition was being filled in as a string. By making one more adjustment, and forcing it to be a number, the solution worked beautifully! Here's the final working version:
FINAL:
xdXDocument:GetDOM("Customers")/dfs:myFields/dfs:dataFields/d:Customers/@CompanyName[../@ContactName = xdXDocument:get-DOM()/my:myFields/my:Customers/my:Customer[number(xdXDocument:GetDOM("Support")/Support/RowPosition)]/@my:Name]
There are other issue to tackle too, such as having a drop-down list box in each row of a table can quickly become a huge performance hit. If you are using a Master-Detail table, you can move the drop-down list box into the Detail table. This will certainly help as you will then only have a single source for the list instead of one per row.
2004-07-03
I uncovered this bug today while trying to figure out why an InfoPathDev example form I've been preparing hasn't been working correctly. I've reported it to my Microsoft contacts, but it is unlikely that there will be any fix for this in SP1 before it ships. This bug has caused me grief for a long time, and I finally figured out why.
I have a Rule on a control with a condition that I built using the InfoPath UI formula builder.
The expression that InfoPath created for me was this:
msxsl:string-compare(., count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1) > 0
But the problem is that InfoPath is forcing the condition to be validated as a string compare. Because of this false positives and negatives are returned in certain circumstances. For example, the string comparison of "4" > "10" will return TRUE.
The expression I was trying to get was the following:
. > (count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1)
With the hand-made adjustment to the expression I am now comparing actual values instead of strings. This gives me the correct result of FALSE for a value comparison of 4 > 10.
By manually updating the rule condition, the change will stay intact until you open the rule condition using the InfoPath UI again. Then it reverts back to using msxml:string-compare(). If you click cancel, your manual update is retained, but if you click OK you will have to fix it again.
I consider this a data loss situation, because A) InfoPath did not give me the intended results when I first created the condition, and B) any time I make a change to the condition, it reverts back.
The problems are that A) I did not know up-front that InfoPath was creating a string comparison, B) it took a lot of time to debug the problem, C) when the condition is modified, I’ll likely not remember that I need to manually modify the expression until I find that the form isn't function properly, and D) whenever someone else makes a change, they may never figure it out!
If I post an example that uses this technique, and others were playing around in the rules to see what I did, A) they would never see the correct condition I manually created because InfoPath will automatically convert the expression back to using msxml:string-compare(), and thus they'll never be able to figure out how I made it work, B) after they look at the condition, the form may no longer function as intended, and C) unless I document this well, they'll never be able to create the same condition expression that I did.
2004-07-09
The InfoPath team responded to me today. Their email sparked an idea for a possible workaround, which ultimately did work. I'll discuss that solution after reviewing their comments and the two recommendations they gave, both of which work. I'll explain why one of their recommendations is good in some circumstances, and not in others. I'll also explain why their other recommendation will always work, as will mine. A member of the InfoPath team took a stab in the dark and made the assumption that my current node (represented by the dot in the expression) was a string datatype. He was correct. Because of this InfoPath defaulted to a string-based comparison. This was why it kept adding the msxsl:string-compare() function. The first recommendation that the InfoPath team gave me was to changing the string datatype into a number datatype. For my example I was creating, this was the correct approach. Making this change, InfoPath recognized the Integer datatype and left out the string comparison. This change is great when you have control over the schema and it makes sense (as was my case) to use a number datatype for the field in question. There are many times when this will not be the case. So another fix is needed. The second recommendation that the InfoPath team gave me was to create my own comparison function. You can do this by writing a function in code that in this case checks if value A is greater than value B. In my particular case I would write a function called IsGreater() which accepts either two numeric values or two nodes. Then in the rules I would call into this function using xdExtension like this:
xdExtension:IsGreater(., count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1)
The function should return a boolean (true/false).
This solution is great because you can do whatever you want in code. You can get as complex as needed, with the entire XDocument DOM at your disposal. But many people do not want to write code, and some people don't know how to. This is also a bit more complex for the as simple a task as I was trying to do.
So now on to my solution. The idea I had while reading their replies to me was that if I just add an XPath function number() around the current node (represented by the dot), that this should be enough to keep InfoPath from being able to "resolve" the XPath into something it can understand, thus forcing it to leave it alone. This too worked—and is much simpler than writing your own function, though less robust. Thus the resulting expression looked like this:
number(.) > count(../my:Items/my:Item) - xdMath:Nz(../my:NumberOfRows) + 1)
So there you have it—three solutions to a troubling problem. The biggest problem now is just recognizing that your condition is being modified. The only way to do that is to edit the condition and then change the first drop-down list box in the Condition dialog box to be "The expression". This allows you to see the full XPath expression to see if it is what you are expecting it to be. It is different, one of these workarounds should do the trick!
Status: Not fixed as of the InfoPath 2003 SP2 release.
I uncovered this bug merely on 2004-07-03 and reported it to my Microsoft contacts.
I discovered that you can get a button into a depressed state and have it stuck there until you release it with another click. It's really not a hard thing to do. And what's worse is then when the button is placed into this state it will not perform its assigned functionality because the click was never released. It is not until the click is released that the rules and code behind the button are processed.
Here are the steps:
Results: The button stays in a depressed state.
Results: The button returns to normal state.
Results: The rule did not fire.
Results: The rule fires.
You can also use a UI.Alert() in place of the rule and the effect is the same. If you use both a rule and an Alert, the affect is the same, only when the button is finally released, the rule fires and then the code, as expected.
I wrote to my Microsoft contact a while back to request that a future version of InfoPath make the repeating sections smart enough to realize that they have hit the specified min or max limit and then hide the appropriate widget for insert or remove.
But while trying to discover a way to work around that, I noticed that the error message that pops up when a min or max condition is hit happens before, and instead of, the OnBeforeChange() event handler. This is bad because there is no way for the form developer to show their own error message. Instead you are stuck with the default cryptic error message that InfoPath supplies, namely:
On insert:
InfoPath cannot insert the section or row because of an error.Details:The attempted fragment operation cannot be completed because there is no valid insertion point for the fragment.
InfoPath cannot insert the section or row because of an error.
Details:The attempted fragment operation cannot be completed because there is no valid insertion point for the fragment.
On remove:
The item cannot be removed.Details:Content for element '{http://schemas.microsoft.com/office/infopath/2003/myXSD/2004-07-01T23:47:14}group1' is incomplete according to the DTD/Schema.
The item cannot be removed.
Details:Content for element '{http://schemas.microsoft.com/office/infopath/2003/myXSD/2004-07-01T23:47:14}group1' is incomplete according to the DTD/Schema.
Another idea I had while playing with this, and recommended Microsoft implement in conjunction with the aforementioned idea is: Allow rules to separately control the insert and delete widgets and the menu items that appear.
So for example, if you have a limit of 10 rows, but you only want the user to insert 3 a maimum of 3 rows under a certain condition, then you could set a rule that would disable the "Insert" feature until the condition was no longer valid. The same thing would work for removing rows.
These would be very powerful and very useful.
STATUS: Fixed in InfoPath 2003 SP1
DESCRIPTION:
While working on a project for Microsoft, Patrick Halstead and I were using some complex Open Rules and were having trouble getting things to work right. So, under the pressure of a deadline, we decided to convert them to code in the OnLoad event handler. It was during this process that we uncovered this bug on 2004-03-19 and reported it to our Microsoft contacts. It was at that point unknown to Microsoft. After this our only solution was to convert back to using Open Rules, which, as complex as they were, we eventually resolved our issues and get them to work as desired.
This bug is managed code specific, meaning it will not happen when using script. It is manifest when attempting to switch views in the OnLoad event handler, but only after the form has been cached locally.
The first time you run the form, when it has not yet been cached, the view will switch as expected, but there-after, until you clear the form from the InfoPath form cache, the view will fail to switch.
If you want see this happen, try this little experiment:
thisXDocument.ViewInfos[1].IsDefault = true;
BUG: The form opens to view 1.
This can be a very bad bug if the need arises for it. So what can be done? The workaround is to use Open Rules to do your view switching. If you have complicated code to figure out which view to switch to, this may not be a viable alternative. But fortunately, most view switching during the OnLoad stage will be able to be accomplished in the Open Rules.
Help is available for InfoPath as part of its installation. But one particular help file is, in my opinion, more useful than the others. Depending on your installation path it can be found at:
C:\Program Files\Microsoft Office\OFFICE11\1033\MSE10.CHM
Why do I find this one so useful? Basically because it combines numerous help files into one. Here are the highlights:
As you can see there is a lot of information contained in this one help file! Make a shortcut to it somewhere where you can easily access it, whether it be using a keyboard shortcut, on your Start menu, or in your Quick Launch Toolbar.
As you are developing your InfoPath forms, you will undoubtedly have a need for the information contained in one or more sections of this help file.
STATUS: Fixed in InfoPath 2003 SP2.
SCOPE: SP1 Managed Code.
DESCRIPTION:I uncovered this bug on 2004-03-08 and reported it to my Microsoft contacts. It was at that point unknown to Microsoft.
This bug is managed code specific, meaning it will not happen when using script. It is manifest when populating an xdCombo box control from the main DOM or from a secondary data source. Initially everything will work fine. But once the view has been roundtripped in the designer, the conditional formatting will be removed from this control.
WORKAROUNDS:
STATUS: Potentially fixed in InfoPath 2003 SP2.
DESCRIPTION:I uncovered this bug on 2004-02-17 and reported it to my Microsoft contacts. It was at that point unknown to Microsoft.
The rules that you defined actually remain in the manifest. The bug is that the xsf:domEventHandlers block goes *POOF*! One way for this to happen is if you open the manifest.xsf file in the Visual Studio editor after rules have been created. But there are others.
Since the xsf:ruleSets block is still in the manifest, you could potentially attempt to establish stub rules for your controls and then manually reattach the domEventHandler to the correct ruleSet. But this may be more work than is worth the effort!
Having said all this, it can still be be very annoying and very problematic to have your rules disappear. But there are a couple of things that I do, in the mean time, to avoid getting hit by this problem. You may find them useful too:
WORKAROUNDS:One workaround is to replace rules with code in the OnAfterChange event. But this may not always be preferred.
I know it's a pain and inconvenient. And unfortunately you are one of the few of us who do the kinds of things that cause this. Just be patient and play by the rules I outlined above and you should be good to avoid it.
In InfoPath SP1, the order of processing at startup of a form is:
The User Roles are processed first so that when the Open Rules are evaluated that they can take into account the current role. The Open Rules can be used to change the default view. Then, after these have processed, the OnLoad event handler will take over. At this point the View object doesn't exist and any functionality requiring it will fail. As a result, you cannot switch views at this point, but can change the default view. Lastly the default view is created and the OnSwitchView event handler is called.
DAY 1 (2004-06-24)
I was just working with a set of forms where a non-managed code (i.e. JScript)—hereafter referred to as NMC—form launches a managed code (i.e. C#)—hereafter referred to as MC—form and passes in its data using the new InfoPath 2003 SP1 method NewFromSolutionWithData. I ran into a bug that I have Microsoft tracking down as I write.
The problem occurs only when managed code is involved. It is related to the Preview version of InfoPath 2003 SP1. I expect it will be fixed in the release version of SP1.
If I use the NewFromSolutionWithData method going from a NMC form to another NMC form, then the problem does not present itself. But if I go from a NMC form to a MC form, or if I got from a MC form to either a NMC or MC form, the problem appears.
So what exactly is the problem? The problem is that 2 of the 3 processing-instructions (PIs) that appear at the top of an InfoPath .xml file get striped out, namely the PI and the PI.
Missing the former PI is not a great loss, but without that latter PI, Windows does not know that the .xml file belongs to InfoPath and will therefore not attempt to open it using InfoPath. Also this will result in the .xml file not having the InfoPath icon to identify it.
Luckily, most InfoPath developers will not encounter this situation. A possible work around, if you know you will get hit by this bug, is to use the OnLoad event handler to manually add the missing PIs back into the XML. I haven't tested this yet, but believe it will work.
DAY 2 (2004-06-25)
Having played around a little with the code, my initial hunch was correct, there is a workaround and it is using code. This will require that you establish some way of knowing that your form was opened using the NewFromSolutionWithData method, and then in the OnLoad event handler you can add the following code:
C#IXMLDOMProcessingInstruction oXML = thisXDocument.DOM.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");IXMLDOMProcessingInstruction oPI = thisXDocument.DOM.createProcessingInstruction("mso-application", "progid=\"InfoPath.Document\"");thisXDocument.DOM.insertBefore((IXMLDOMNode)oPI, thisXDocument.DOM.firstChild);thisXDocument.DOM.insertBefore((IXMLDOMNode)oXML, thisXDocument.DOM.firstChild);JScriptvar oXML = XDocument.DOM.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");var oPI = XDocument.DOM.createProcessingInstruction("mso-application", "progid=\"InfoPath.Document\"");XDocument.DOM.insertBefore(oPI, XDocument.DOM.firstChild);XDocument.DOM.insertBefore(oXML, XDocument.DOM.firstChild);
Thus, when the form is saved, the two missing PIs will be back in place and your form will be ready to roll.