Managing Task Panes in Multiple Word and InfoPath Documents
Summary: Custom task panes in Microsoft Office Word 2007 and Microsoft Office InfoPath 2007 are attached to each open document individually. Learn how to manage custom task panes when the user has multiple documents open. (19 printed pages)
Robert Green, MCW Technologies, LLC
Applies to: Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System, Microsoft Office Word 2007, Microsoft Office InfoPath 2007
Overview of Task Panes in Microsoft Office
Microsoft Office 2003 introduced the Document Actions task pane. A task pane is a panel that can be docked to the side of the document workspace to provide contextual assistance to users. Microsoft Visual Studio 2005 Tools for the Microsoft Office System enables you to create custom Document Actions task panes that you can attach to Microsoft Office Word 2003 documents and Microsoft Office Excel 2003 workbooks.
Custom task panes in Office 2003 belong to a single document or workbook. For example, you might create a custom task pane that assists users when they fill out expense reports in Excel. You can attach a task pane to an Excel template so that each time users create new expense reports from that template, they can access the task pane.
A document-level task pane is fine when the task pane provides assistance in a single document, workbook, or template. However, some scenarios require that task panes be available no matter which document is open. For example, you might create a custom task pane that enables users to insert standard text into Word documents. Users might want the ability to use this task pane in any document.
To provide this capability in Office 2003, you could attach the task pane to a template and then require users to create new documents from this template. The task pane would then be attached to all documents created from this template, but would not be attached to any other document.
The 2007 release of the Microsoft Office system expands the custom task pane model. Custom task panes are now available at the application level in addition to the document level. Rather than attaching a task pane to a specific document or template, you can essentially attach the task pane to the application. You accomplish this by creating the custom task pane as a COM add-in.
Custom task panes are available in the following applications:
Microsoft Office Access 2007
Microsoft Office Excel 2007
Microsoft Office InfoPath 2007
Microsoft Office Outlook 2007
Microsoft Office PowerPoint 2007
Microsoft Office Word 2007
You can create custom task pane add-ins by using Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System (also called Visual Studio 2005 Tools for Office Second Edition). For more information, see Creating Custom Task Panes Using Visual Studio 2005 Tools for the Office System SE. Note that Visual Studio 2005 Tools for Office Second Edition does not support creating custom task panes for Access 2007.
Understanding Custom Task Panes and Their Parent Windows
A document-level customization is attached to a single document. If the customization creates a custom task pane, that task pane is hosted by that document. If you open a second document, the task pane does not appear, unless that document's customization creates it.
If an application-level customization creates a custom task pane, you would expect that task pane to appear regardless of what document is open. In Excel 2007 and PowerPoint 2007, that is the behavior by default. In Word 2007 and InfoPath 2007, however, you need to write code to open multiple task panes. This article explores that code and the reasons for it.
First, compare the behavior of Excel and Word. Start Excel. Click the Review tab on the Ribbon. Click the Research button to bring forward the Research task pane. Next, create a new workbook. Notice that the Research task pane is still visible. Switch back to the first workbook. Close the Research task pane. Switch to the second workbook. The Research task pane is gone.
Start Word. Click the Review tab on the Ribbon. Click the Research button to bring forward the Research task pane. Next, create a new document. Notice that the Research task pane is not visible. Click the Review tab on the Ribbon. Click the Research button to bring forward the Research task pane. Switch back to the first document. Close the Research task pane. Switch to the second document. The Research task pane is visible.
This behavior is not new in the 2007 release of Office. Microsoft Office 2003 applications behave the same way.
Differences Between Document Frame Windows
The custom task pane is always hosted by a document frame window. As the name implies, the role of the document frame window is to present to the user a view of a document. That document might be a Word document, an Excel worksheet, or a PowerPoint slide, for example.
Excel and PowerPoint create one document frame window. You can have multiple workbooks or presentations open, but they are all displayed in the same document window. That is why the Research task pane was always visible after being brought forward, regardless of which workbook was active.
By default, Word creates a document frame window for each open document. When you bring forward a custom task pane, it is hosted by the currently active document window. When you switch to another document, you are switching to another document window. That is why the Research task pane was not visible when you switched to another document. InfoPath behaves the same way.
You can change the behavior of Word to be like that of Excel and PowerPoint by opening Word 2007 and clicking the Microsoft Office Button. Click Word Options, and then click Advanced. Scroll to the Display options and clear Show all windows in the Taskbar. Word will now create one document frame window. All open documents will be displayed in the same document window.
In Outlook, Explorers display the contents of folders, such as the Inbox or Calendar, and Inspectors display the contents of items in a folder, such as e-mail messages or appointments. Outlook appears to behave the same way that Excel and PowerPoint do, but in fact, it behaves like Word and InfoPath. Outlook creates a document frame window when you start it. You can switch from one folder, for instance the Inbox, to another, for instance the Calendar, and remain in the same document frame window. A task pane attached to that window remains visible when you switch views.
However, you can open additional Explorers in their own windows. For example, you can right-click Contacts and then click Open in New Window. You can do the same for a folder in your Inbox. The new Explorer window is hosted in its own document frame window and a task pane attached to any other Explorer window will not be attached to the new window. The same is true for Inspector windows.
This behavior is interesting but not necessarily relevant if you are building a document-level custom task pane. A document-level custom task pane belongs to a single document. You build a customization based on a specific document or template, and the customization code includes the user interface for the task pane and the code to have the task pane appear to the user. Because you attach the customization code to the specific document, the custom task pane appears only when the document window displays that document.
Document frame window hosting is not an issue if you are building an application-level custom task pane for Excel or PowerPoint. Your task pane appears regardless of the currently active document or presentation.
However, if you are building an application-level custom task pane for Word, InfoPath, or Outlook, you need to figure out what steps to take in your code to have the custom task pane appear in all documents. You need to ensure that the task pane appears in each document frame window, and that it appears only once. The rest of this article explores techniques for managing application-level custom task panes in Word and InfoPath.
Managing Task Panes in Multiple Documents
To ensure that your custom task pane is available in all document windows, monitor the following user actions:
The user takes an action to display or hide a task pane.
The user creates a new document.
The user opens an existing document.
The user closes an open document.
You can manage task panes by using the appropriate event handlers.
The User Takes an Action to Display or Hide a Task Pane
A good user interface practice is to provide users with the ability to display task panes when they are needed and to hide the task panes when they are not needed.
In applications that support the Ribbon, including Word, you can customize the Ribbon and include a button on the Add-Ins tab that opens and closes the task pane. In applications that do not support the Ribbon, including InfoPath, you can add a menu item that displays and hides the task panes.
The sample Word add-in uses the following method to add a custom task pane to all open document windows. The task pane contains a calendar control.
The following code first checks whether any documents are currently open. If so, the code next checks whether the user is displaying all windows in the Taskbar. If so, the code loops through each open Word document and calls the AddCalendarTaskPane method, passing the document as a parameter. If the user is not displaying all windows in the Taskbar, the code calls this method once, passing the current document as a parameter.
Public Sub AddAllCalendarTaskPanes() If Globals.ThisAddIn.Application.Documents.Count > 0 Then If Me.Application.ShowWindowsInTaskbar Then For Each _doc As Word.Document In Me.Application.Documents AddCalendarTaskPane(_doc) Next Else If Not calendarDisplayed Then AddCalendarTaskPane(Me.Application.ActiveDocument) End If End If calendarDisplayed = True End If End Sub
The Word version of the AddCalendarTaskPane method is as follows. The code creates a new custom task pane and adds it to the collection of custom task panes that belong to this add-in. The first two arguments of the Add method specify a control to add to the custom task pane and the title to display on the task pane. The third argument, which is optional, specifies the parent window for the custom task pane. If this argument is not included, the currently active window hosts the custom task pane. The code passes each open document's window to the Add method to specify the parent window.
After creating each custom task pane, the code sets the Visible property to true to display the custom task pane.
Public Sub AddCalendarTaskPane(ByVal doc As Word.Document) ctpCalendar = Me.CustomTaskPanes.Add( _ New CalendarControl(), "Select a date", doc.ActiveWindow) ctpCalendar.Visible = True End Sub
The AddAllCalendarTaskPanes method is as follows in the sample InfoPath add-in.
Public Sub AddAllCalendarTaskPanes() For Each _window As InfoPath.Window In Me.Application.Windows AddCalendarTaskPane(_window) Next End Sub
The InfoPath version of the AddCalendarTaskPane method is as follows.
Public Sub AddCalendarTaskPane(ByVal _window As InfoPath.Window) ctpCalendar = Me.CustomTaskPanes.Add( _ New CalendarControl(), "Select a date", _window) ctpCalendar.Visible = True End Sub
The sample Word add-in adds a group to the Add-Ins tab on the Ribbon. The group contains an Insert date button. When the user clicks that button, the following code runs.
Public Sub CalendarButtonClick(ByVal control As Office.IRibbonControl) If Not Globals.ThisAddIn.showCalendar Then Globals.ThisAddIn.AddAllCalendarTaskPanes() Else Globals.ThisAddIn.RemoveAllCalendarTaskPanes() End If End Sub
The sample InfoPath add-in adds a VSTO Add-ins item to the main menu. That menu contains an Insert date item. When the user clicks that item, the following code runs.
Private Sub taskPaneMenu_Click( _ ByVal ctrl As Office.CommandBarButton, ByRef CancelDefault _ As Boolean) showCalendar = Not showCalendar If showCalendar Then AddAllCalendarTaskPanes() Else RemoveAllCalendarTaskPanes() End If End Sub
If the calendar custom task pane is not currently visible, the code in the AddAllCalendarTaskPanes method runs to add the task pane to all open documents. If the task pane is visible, the code in the RemoveAllCalendarTaskPanes method runs to remove the task pane from all open documents.
If you could have only one custom task pane per document, the RemoveAllCalendarTaskPanes method could look like the following code.
For Each _ctp As Microsoft.Office.Tools.CustomTaskPane In _ Me.CustomTaskPanes Me.CustomTaskPanes.Remove(_ctp) Next
However, multiple custom task panes can be open at the same time. You do not necessarily want to remove all of them. The following code removes only the calendar custom task panes. This method is the same in the Word add-in and the InfoPath add-in.
Public Sub RemoveAllCalendarTaskPanes() For i As Integer = Me.CustomTaskPanes.Count To 1 Step -1 ctp = Me.CustomTaskPanes.Item(i) If ctp.Title = "Select a date" Then Me.CustomTaskPanes.RemoveAt(i) End If Next End Sub
The code above loops through each of the custom task panes that belong to the add-in. The code earlier defined the variable ctp as an instance of Microsoft.Office.Tools.CustomTaskPane. If a task pane is a calendar task pane, the code removes that custom task pane. This code removes only the task panes that are added by this add-in. It does not remove task panes that are added by different add-ins.
The User Creates a New Document
When the user creates a new Word document, the NewDocument event occurs. The following code is the event handler for this event.
Private Sub Application_NewDocument(ByVal Doc As Word.Document) _ Handles Application.NewDocument If showCalendar And Me.Application.ShowWindowsInTaskbar Then AddCalendarTaskPane(Doc) End If End Sub
If the user is not showing all windows in the Taskbar, creating a new document has no effect on the custom task pane. If a task pane is attached to the document frame window before the user creates a new document, the task pane stays attached and visible. If it is not attached and visible, it remains not attached or visible. If the user is showing all windows in the Taskbar and the other open documents display the custom task pane, the new document window also displays it.
When the user creates a new InfoPath document, the NewXDocument event occurs. The following code is the event handler for this event.
The code calls the AddCalendarTaskPane method, passing the newly created Word document or the active InfoPath window as a parameter. The method creates a calendar custom task pane, and specifies the new document's window as the parent.
This code first calls the AddMenu method to add the VSTO Add-ins menu to the new document's window.
The User Opens an Existing Document
When the user opens an existing Word document, the DocumentOpen event occurs. It might seem as though you should call the AddCalendarTaskPane method in the DocumentOpen event handler, just as you did from the NewDocument event handler. Although this works, it is inefficient code.
Private Sub Application_DocumentOpen(ByVal Doc As Word.Document) _ Handles Application.DocumentOpen If showCalendar And Me.Application.ShowWindowsInTaskbar Then AddCalendarTaskPane(Doc) End If End Sub
To understand why this is inefficient, consider the following exercise:
Start Word. Document1 is active and empty.
On the Ribbon, click the button to show the task pane. The custom task pane appears in Document1.
Now open an existing document. Document1 closes and the only open document is the existing one.
The custom task pane appears in the existing document. However, the custom task pane hosted by the Document1 window still exists. The CustomTaskPanes collection contains two items: the task pane hosted in the currently active window, and a task pane hosted by no window.
When Document1 closes, you should remove the custom task pane it hosted. What event can you use? You cannot use the DocumentBeforeClose event or the Document.Close event. Word does not raise either of these events when you open the existing document. Word is essentially just replacing the document in the document frame window. You also cannot use the DocumentChange event because this event occurs every time the active document changes—in other words, every time you switch to a different document window. In fact, there is no event associated with starting Word with a new document and then opening an existing document.
Instead of reactively cleaning up orphaned task panes after you open an existing document, you can proactively clean up by calling the following method from the DocumentOpen event handler before you call AddCalendarTaskPane. This code loops through each of the custom task panes that belong to the add-in. If the task pane has no associated window, the code removes the task pane from the collection.
Private Sub RemoveOrphanedTaskPanes() For i As Integer = Me.CustomTaskPanes.Count To 1 Step -1 ctp = Me.CustomTaskPanes.Item(i) If ctp.Window Is Nothing Then Me.CustomTaskPanes.Remove(ctp) End If Next End Sub
The DocumentOpen event handler now contains the following code.
Private Sub Application_DocumentOpen(ByVal Doc As Word.Document) _ Handles Application.DocumentOpen RemoveOrphanedTaskPanes() If showCalendar And Me.Application.ShowWindowsInTaskbar Then AddCalendarTaskPane(Doc) End If End Sub
When the user opens an existing InfoPath document, the XDocumentOpen event occurs. The XDocumentOpen event handler in the sample add-in is as follows. This code calls the RemoveOrphanedTaskPanes method for the same reasons the Word add-in calls this method. The code in the RemoveOrphanedTaskPanes method is the same in the Word and InfoPath add-ins.
Private Sub appevents_XDocumentOpen( _ ByVal pDocument As InfoPath._XDocument) _ Handles appevents.XDocumentOpen AddMenu() RemoveOrphanedTaskPanes() If showCalendar Then AddCalendarTaskPane(Me.Application.ActiveWindow) End If End Sub
The InfoPath XDocumentBeforeClose and XDocumentChange events have the same behavior as the Word DocumentBeforeClose and DocumentChange events.
The User Closes an Open Document
When the user closes a Word document, the DocumentBeforeClose and Document.Close events occur. When the user closes an InfoPath document, the XDocumentBeforeClose event occurs. These events actually occur just before the document closes, not after it closes. These events occur before Word or InfoPath prompts the user to save outstanding changes. If the user clicks Cancel instead of saving the document, the document does not close. Therefore, if you put code in either of these events to remove the custom task pane, the code can remove the task pane from a document that the user did not close.
One option to prevent removing a task pane from an open document is to use a custom Close dialog box instead of the built-in one. You can then run the code to remove the task pane after the user responds to the prompt.
Another option is to call the RemoveOrphanedTaskPanes method from the DocumentChange event in Word and from the XDocumentChange event in InfoPath. This event occurs when the active document changes, and so occurs after a document is closed. It also occurs when the user opens a new or existing document, and when the user switches from one open document to another. The benefit of removing orphaned task panes when the user closes a document is somewhat offset by the overhead of searching for orphaned task panes every time the active document changes.
The DocumentChange event handler in the Word add-in is as follows.
Private Sub Application_DocumentChange() Handles Application.DocumentChange RemoveOrphanedTaskPanes() End Sub
The DocumentChange event handler in the InfoPath add-in is as follows.
Maintaining Consistent Behavior in Task Panes in Multiple Windows
The custom task pane in the sample add-ins contains a calendar control. The user can select a date and click Insert date to insert that date into the current document. If the user switches to another open document, does she expect the calendar in that window's task pane to display the same date as the calendar in the previous window's task pane?
In Excel or PowerPoint, there would be one instance of this task pane. Switching from one open workbook or presentation does not change the state of the task pane (unless you write code to change it).
In Word and InfoPath, you have a choice. The default behavior is that each task pane maintains its own state. You have multiple instances of the custom task pane and they are independent. In some cases, this might not be the behavior you want. You might want to write code to maintain state across the various task panes. On the other hand, it provides the opportunity to build richer solutions. You can decide, for each solution, whether you want task panes to be independent or to share state.
Sharing State Across Multiple Task Panes
One option for sharing state across multiple task panes is to update the task pane in each document when it becomes active. When you create the first task pane, you can store its state. In the DocumentChange event handler in Word or the XDocumentChange event handler in InfoPath, or in the WindowActivate event handler in either, you can update the custom task pane hosted by the now-active window.
A potential problem with this approach is that Word and InfoPath display the now-active window before the code in these events runs. The user sees the custom task pane in its original state, and then sees it updated to its new state.
An alternative approach is to update each of the other task panes when data in the current task pane changes. That is the approach taken in the sample add-ins.
When the user changes the date in the calendar control, the following code runs in Word. This code first stores the selected date to the global calendarDate variable. It then loops through each of the custom task panes looking for calendar task panes that do not belong to the currently active window. _ctp.Control represents the user control in the custom task pane. _ctp.Control.Controls["monthCalendar1"] represents the calendar control. The date of that control is set to the date the user just selected.
Globals.ThisAddIn.calendarDate = Me.MonthCalendar1.SelectionStart For Each _ctp As Microsoft.Office.Tools.CustomTaskPane In _ Globals.ThisAddIn.CustomTaskPanes ctpWindow = CType(_ctp.Window, Word.Window) If _ctp.Title = "Select a date" And _ ctpWindow IsNot Globals.ThisAddIn.Application.ActiveWindow Then _monthCalendar = CType( _ _ctp.Control.Controls("monthCalendar1"), MonthCalendar) _monthCalendar.SelectionStart = _ Me.MonthCalendar1.SelectionStart End If Next
The InfoPath version of this code is the same, except for the following line of code.
When the user opens a new or existing document, the add-ins create a calendar custom task pane. The following modification to the Word version of the AddCalendarTaskPane method ensures that the calendar control on the new task pane displays the same date as the other task panes.
Public Sub AddCalendarTaskPane(ByVal doc As Word.Document) ctpCalendar = Me.CustomTaskPanes.Add( _ New CalendarControl(), "Select a date", doc.ActiveWindow) _monthCalendar = CType( _ ctpCalendar.Control.Controls("monthCalendar1"), MonthCalendar) _monthCalendar.SelectionStart = calendarDate ctpCalendar.Visible = True End Sub
The InfoPath add-in includes the same modification to the AddCalendarTaskPane method.
Custom task panes in the 2007 release of Microsoft Office add flexibility and power to the solutions you create by using Visual Studio Tools for Office. You can create custom task panes that exist at the application level and task panes that you attach to a specific document. This additional capability enables you to create custom task panes that meet more of your user requirements.
The sample add-ins used in this article create a custom task pane for each open Word or InfoPath document. You can use the techniques explored here to cause the custom task panes to behave like task panes in Excel and PowerPoint. You can also let the user control task panes at the document level. It is a design decision whether to use a Ribbon button or a menu item to display a custom task pane for all open documents or for only the currently active document.
About the Author
To learn more about the products and technologies mentioned or used in this article, see these resources: