InfoPath SP1 (public beta at the link; final due out this summer) includes a lot of cool changes, both in the UI and behind the scenes (most notably the ability to stuff managed code behind the form). First I'm going to cover the OnContextChange event and using it to create context-sensitive help.

To create a managed code InfoPath form, you need to download the InfoPath Toolkit for Visual Studio .Net - this provides the templates for InfoPath in VS. Once installed, open Visual Studio, create a new project, select Microsoft Office InfoPath Projects, then either “Visual Basic Projects” or “Visual C# Projects” (I'll be using C#), and “InfoPath Form Template” from the “Templates” pane.

Name your project, click “OK” and you've got an InfoPath project and form. (Also notice that under the “Project” menu in Visual Studio you've got some new InfoPath commands, most notably “Open InfoPath” for those times you close the form designer)

So, for our context-sensitive help we're going to need an HTML file containing the help. Create your file - all you really need to do is append all the help paragraphs/articles into a single file. The way I handled context sensitivity is to wrap each help segment into a DIV, then hide all the DIVs and show the appropriate DIV based on the control selected. Other possibilities include using HTML anchors and scrolling to the anchor for the article, or even creating a document with an empty DIV, then pulling the text from another location and dynamically inserting it into the document.

So, I have an HTML document with a series of DIVs. I used FrontPage 2003 because I found the layer handling helped out a lot. (View | Task Pane, then in the Task Pane menu at the top select “Layers”) You'll want each layer/DIV to use the following tag:

<div style="position: absolute; visibility: hidden; left: 0px; top: 0px" id="[Name]">

For [Name] use the control name for the control you want the DIV associated with.

[Thanks to Josh Bertsch for help with the following code, C# and jscript]

Now add the following jscript to the <HEAD> of the file:

<script>
 var g_anchor="";
 function waitForContext(anchor)
 {
  g_anchor=anchor;
  window.setTimeout("setTaskPaneLoc();", 1000);
 }
 
 function setTaskPaneLoc(aLoc)
 {
  var aLoc=g_anchor;
  var aCol=document.all.tags("DIV");
  var aColLen=aCol.length;
  
  var anchorNames="";
  
  for(var i=0; i<aColLen; i++)
  {
   anchorNames+=aCol[i].id + "; ";
   if(aCol[i].id==aLoc)
   {
    aCol[i].style.visibility="visible";
   }
   else
   {
    aCol[i].style.visibility="hidden";
   }
  }
 }
</script>

This will, after a 1-second pause, zip through the DIV tags in the file, showing the one whose ID is the same as the control name, and hiding the rest.

Once you're happy with the file, in InfoPath go to Tools | Form Options, then the Advanced tab. In the “Custom Task Pane“ section check “Enable custom task pane”, then click the “Resource Files“ button and add your file. (NOTE: if you change your help file later, you'll have to go to this option, remove the file and add it again, otherwise you won't see your changes). Once you've added the file, then it should be available in the drop-down for “Task pane location“ - select it.

Now, in InfoPath go to the Tools Menu, Programming, and click “On Context Change Event“ - this will create and take you to the OnContextChange event handler in the VS.Net IDE.

Add a reference in the project to Microsoft.mshtml.

Use this code in your OnContextChange handler:

if (e.Type == "ContextNode")

{

string aLoc=e.Context.nodeName;

aLoc=aLoc.Replace("my:", "");

HTMLTaskPaneObject taskPane=(HTMLTaskPaneObject)thisXDocument.View.Window.TaskPanes[0];

mshtml.HTMLWindow2Class window=(mshtml.HTMLWindow2Class)taskPane.HTMLDocument.Script;

window.execScript("waitForContext('" + aLoc + "')", "JScript");

}

That should do it - now just remember that the DIV id has to be the same as the name of the control. Also watch out for width/height definitions on the DIVs - best to just let the task pane do the formatting.

Philo