Example Application C# Help

As mentioned in previous sections, the example code for this chapter includes an application called WordDocEditTimer, which maintains a list of edit times for Word documents. In this section, we
examine the code for this application in detail, as it illustrates everything you’ve read about so far and includes some useful tips.

The general operation of this application is that whenever a document is created or loaded, a timer is started, linked to the document name. If you close a document, then the timer for that document pauses. If you open a document that has previously been timed, then the timer resumes. Also, if you use Save As to save a document with a different filename, then the timer is updated to use the new filename.

This application is a Word application-level add-in, and uses a custom task pane and a ribbon menu. The ribbon menu contains a button that you can use to turn the task pane on and off and a check box that enables you to pause the timer for the currently active document. The group containing these controls is appended to the Home ribbon tab. The task pane displays a list of active timers.

This user interface is shown in Figure 40-13 .

Figure 40-13

Figure 40-13

Capture

This keeps a reference to a Microsoft. Office. Interop. Word. Document object as well as the total edit time, whether the timer is active, and the time it last became active. The ThisAddln class maintains a collection of these objects, associated with document names:

Capture

These event handlers are used to monitor documents as they are opened, created, and closed, and also to ensure that the Pause check box is kept up-to-date on the ribbon. This latter functionality is achieved by keeping track of window activations with the WindowActivate event.

The last task performed in this event handler is to start monitoring the current document and add the custom task panel to the window containing the document:

// Start monitoring active document
MonitorDocument(this.Application.ActiveDocument);
AddTaskPaneToWindow(this.Application.ActiveDocument.ActiveWindow);

The MonitorDocument() utility method adds a timer for a document:
internal void MonitorDocument(Word.Document Doc)
{
//(
Document
EditTime
IsActive
LastActive
Doc,
new TimeSpan(O)
true,
DateTime.Now
)) ;
}

This method simply creates a new DocumentTimer for the document. The DocumentTimer references the document, has zero edit time, is active, and was made active at the current time. It then
adds this timer to the documentEditTimes collection and associates it with the document name.

The AddTaskPaneToWindow() method adds the custom task pane to a window. This method starts by checking the existing task panes to ensure that there isn’t one in the window already. Also, one other
strange feature of Word is that if you immediately open an old document after loading the application, the default Documentl document vanishes, without raising a close event. This can lead to an exception being raised when the window for the task pane that was in the document is accessed, so the method also checks for the ArgumentNullException that indicates this.

Capture

If an exception is thrown, then.the offending task pane is removed from the collection:
// Remove pane if necessary
timerDispldyPanes.Remove(paneToRemove);
If no task pane was found for the window, then the method finishes by adding one:

Capture

The added task pane is an instance of the TimerDisplayPane class. You will look at this class shortly. It is added with the name Document Edit Timer. Also, an event handler is added for the VisibleChanged event of the CustomTaskPane that you obtain after calling the CustomTaskPanes. Add() method. This enables you to refresh the display when it first appears: Capture

The TimerDisplayPane class exposes a RefreshDisplay() method that is called in the preceding code. This method, as its name suggests, refreshes the display of the timerControl object.

Next, there is the code that ensures that all documents are monitored. First, when a new document is created, the eventlnterface_NewDocument() event handler is called, and the document is monitored by calling the MonitorDocument() and AddTaskPaneToWindow() methods, which you’ve already seen.

Capture

This method also clears the Pausecheck box in the ribbon menu as new documents start with the time running. This is achieved through a util!ty method, SetPauseStatus( ), which is defined on the ribbon:
// Set checkbox
Globals.Ribbons.TimerRibbon.SetpauseStatus(false) ;
}

Just before a document is closed, the eventlnterface_DocumentBeforeClose () event handler is called. This method freezes the timer for the document, updates the total edit time, clears the Document reference, and removes the task pane from the document window (with RemoveTaskPaneFromWindow( ), detailed shortly) before the document is closed.

Capture

When a document is opened, the eventlnterface_DocumentOpen() method is called. There is a little more work to be done here, as before monitoring the document, the method must determine whether a timer already exists for the document by looking at its name.

Capture

If the document isn’t already being monitored, then a new monitor is configured as for a new document.

Capture

The,RemoveTaskPaneFromwindow() method is used to remove the task pane from a window. The code for this method first checks that a task pane exists for the specified window:

Capture

If a task window is found, then it is removed by calling the CustomTaskPanes. Remove() method. It is also removed from the local collection of task pane references.

Capture

The last event handler in this class is eventlnterface_WindowActivate(), called when a window is activated. This method gets the timer for the active document and sets the check box on the ribbon menu so that the check box is kept updated for the document:

Capture

The code for ThisAddln also includes two utilitymethods. The first of these ToggleTaskPaneDisplay(), isused to show or hide the display of the task pane for the currently active document by setting the CustomTaskPane. Visible property.

Capture

The ToggletaskPaneDisplay() method shown in the preceding code is called by event handlers on the ribbon control,as you will see shortly.

Finally,the class has another method that is called from the ribbon menu, which enables ribbon controls to pause or resume the timer for a document:

Capture

The only other code in this class definition is an empty event handler for Shutdown, and the VSTO generated code to hook up the Startup and Shutdown event handlers.

Next, the ribbon in the project, TimerRibbon, is laid out, as shown in Figure 40-14.

Figure 40-14

Figure 40-14

This ribbon contains a RibbonButton, a RibbonSeparator, a RibbonCheckBox, and a DialogBoxLauncher. The button uses the large display style, and has an Officelmageld of StartAfterPrevious which displays the clock face shown in Figure 40-13. (These images are not visible at design time.) The ribbon uses the TabHome tab type, which causes its contents to be appended to the Home tab.

The ribbon has three event handlers, each of which calls on one of the utility methods in ThisAddln described earlier:

Capture

The ribbon also includes its own utility method, SetPauseStatus(), which as you saw earlier is called by code in ThisAddln to select or clear the check box:

Capture

The other component in this solution is the TimerDisplayPane user control that is used in the task pane. The layout of this control is shown in Figure 40-15.

Figure 40-15.

Figure 40-15.

This control includes a button, a label, and a list box – not the most exciting of displays, although would be simple enough to replace it with, for example, a prettier WPF control.

The code for the control keeps a local reference to the document timers, which is set in the constructor:

Capture

The button event handler calls the RefreshDisplay() method to refresh the timer display:

Capture

The RefreshDisplay() method is also called from ThisAddln, as you ‘saw earlier. It is a surprisingly complicated method considering what it does. It also checks the list of monitored documents against the list of loaded documents and corrects any problems. This sort of code is often necessary in VSTO applications, as the interface with the COM Office object model occasionally doesn’t work quite as it
should. The rule of thumb here is to code defensively,

The method starts by clearing the current list of timers in the timerList list box:

Capture

Next, the monitors are checked. The method iterates through each document inthe Globals .ThisAddln Application Documents collection and determines if the document is monitored, unmonitored, or monitored but has had a name change since the last refresh.

Finding monitored documents simply involves checking the document name against the document names in the documentEdit Times collection of keys:

Capture

If the names don’t match, then the document references are compared, which enables you to detect name changes to documents, as shown in the following code:

For unmonitored documents, a new monitor is created:

Capture

Whereas documents with name changes are re-associated with the monitor used for the old named document:

Capture

After reconciling the document edit timers, a list is generated. This code also detects whether referenced documents are still loaded, and pauses the timer for documents that aren’t by setting the Is Acti ve property to false. Again, this is defensive programming.

Capture

For each monitor, a list item is added to the list box that includes the document name and its total edit time:

Capture

This completes the code in this example. This example has shown you how to use ribbon and task pane controls and how to maintain task panes in multiple Word documents. It has also illustrated many of the techniques covered earlier in the chapter.

Posted on October 30, 2015 in Visual Studio Tools for Office

Share the Story

Back to Top