VSTO Extensions to Word and Excel Objects


VSTO extends the Word and Excel object models in several ways. Although it is possible to use these features without understanding what is actually happening behind the scenes, it is helpful to take a look back there. This section explains by what mechanisms host items and host controls extend the Word and Excel programming models. Then the discussion focuses on which new features are available.

Aggregation, Inheritance, and Implementation

If you create a Word project in Visual Studio and open the Object Browser window, you will see several assemblies listed. Two are of particular interest. You already know that the Microsoft.Office.Interop.Word assembly is the primary interop assembly (PIA), containing the definitions for the interfaces that allow managed code to call the unmanaged Word object model. Similarly, the Microsoft.Office.Interop.Excel assembly is the PIA for the unmanaged Excel object model.

You can find the VSTO extensions to the Word and Excel object models in the Microsoft.Office.Tools.Word and Microsoft.Office.Tools.Excel assemblies; each contains a namespace of the same name.

From a VSTO Word document project, open the Object Browser, and take a look at the Document host item class in the Tools namespace, shown in Figure 13.2.

Figure 13.2. Examining the Document host item class in the Object Browser.


Notice that the host item class implements the properties, methods, and events defined by the Document interface from the PIA, and extends the BindableComponent base class. Chapter 17, "VSTO Data Programming," gets into the details of how data-bindable components work; for now, the fact that this class implements the properties, methods, and events from the PIA interface rather than extends a base class is important. It is important to notice that even though the Document host item class has all the methods, properties, and events of the Document interface from the PIA, the type definition does not actually say that it implements the Document interface itself. This is a subtle distinction that we will discuss in more detail later.

Conceptually, the difference between extending a base class and implementing the properties, methods, and events from an interface is that the former describes an "is a" relationship, whereas the latter describes a "can act like" relationship. A Microsoft.Office.Tools.Word.Document object really is a bindable component; it actually shares functionalitycodewith its base class. But it merely looks like and acts like a Word Document object; it is not a Word document object as far as Word is concerned.

The Sheet1 class in Excel, for example, has your event handlers and host controls. It extends the Microsoft.Office.Tools.Excel.Worksheet base class and implements the properties, methods, and events defined by the Microsoft.Office.Interop.Excel.Worksheet interface.

Connecting the Aggregates

VSTO's host item and host control objects aggregate some of the underlying Word and Excel document objects (such as the Document and Bookmark objects in Word, and the Worksheet and NamedRange objects in Excel). You have already seen how you can call methods on the document object in a VSTO customization. Suppose that you call the CheckGrammar method on the document. If this is not really a Word Document object but merely looks like one, how does it work?

The aggregating object's implementation of that method checks to see whether it has obtained the aggregated Document object already. If it has not, it makes a call into Word to obtain it (and caches away the object so that it will be available immediately when you make a second method call). After it has the reference to the aggregated object, the aggregating object calls CheckGrammar on the aggregated object. The great majority of the properties and methods on the aggregating objects do nothing more than pass the arguments along to the PIA code, which then passes them along to the unmanaged object model.

Events work in the analogous way; if your code listens to an event exposed by an aggregating object, the aggregating object listens to the event on the aggregated object on your behalf. When the event is raised by the aggregated object, the aggregating object's delegate is called; it raises the aggregating object's event and calls your event handling delegate.

All the host controls are connected in a similar manner to the host items. If you have a NamedRange host control member of a worksheet, for example, the aggregating Worksheet object itself creates an aggregating NamedRange object. The first time you call a method on the host control, the aggregating class obtains the underlying "real" object from Excel and passes the call along.

This might seem like a whole lot of rigmarole to go through just to add new functionality to the Word and Excel object models. The key benefit that this system of aggregates affords is that each host item class in each project can be customized. One spreadsheet can have an InvoiceSheet class with a CustomerNameRange property; another can have a MedicalHistorySheet class with a CholesterolLevelChart property, and so on.

In short, VSTO extends the Word and Excel object models by aggregating the unmanaged object models with managed objects. VSTO enables developers to customize and extend some of those objects furtherthose representing the workbook, worksheet, chart sheet, and documentthrough subclassing.

Obtaining the Aggregated Object

Much of the time, the foregoing details about how the aggregation model works are just that: implementation details. Whether the host item "is a" worksheet or merely "looks like" one seems to be an academic point. In some rare scenarios, however, it does matter.

Word's and Excel's object models were not written with the expectation that managed aggregates would implement their interfaces; when you call a method that takes a range, Excel expects that you are passing it a real range, not an aggregated range that acts like a range.

Suppose that you have a customized worksheet with two host controls: a NamedRange member called InvoiceTotals and a Chart object called InvoiceChart. You might want to write code something like this snippet:

Me.InvoiceChart.SetSourceData(Me.InvoiceTotals, _     Excel.XlRowCol.xlColumns) 


This code will throw an exception at runtime because the SetSourceData method on the chart aggregate must be passed an object that implements the Range interface. It looks like at runtime, the InvoiceChart aggregate will pass InvoiceTotals, an aggregated range, to the "real" aggregated chart. But Excel will expect that the object passed to SetSourceData is a range, whereas in fact it is the VSTO aggregate; it merely looks like an Excel range.

When just calling methods, reading or writing properties, and listening to events, the aggregate is more or less transparent; you can just use the object as though it really were the thing it is aggregating. If for any reason you need to pass the aggregate to an Excel object model method that requires the real Excel object, you can obtain the real Excel object via the InnerObject property. The code above will work properly if you rewrite it to look like this:

Me.InvoiceChart.SetSourceData(Me.InvoiceTotals.InnerObject, _     Excel.XlRowCol.xlColumns) 


Aggregation and Windows Forms Controls

If you drag and drop a Windows Forms button onto a worksheet or document, the button control is also aggregated. Windows Forms controls, however, are aggregated slightly differently from the NamedRange, Bookmark, ListObject, and other controls built in to Word and Excel. There are two relevant differences between Windows Forms controls and Office's controls. First, Windows Forms controls are implemented by extensible managed classes, unlike the unmanaged Office controls, which only expose interfaces in their PIAs. Second, Word and Excel controls inherently know how they are situated in relation to their containing document or worksheet; non-Office controls on a worksheet do not know that they are in a worksheet.

Word and Excel overcome the second difference by aggregating an extender onto a control sited on a document or worksheet. Word's extender implements the properties, methods, and events of the_OLEControl interface that can be found in the Word PIA (but as with other aggregated VSTO controls, the type definition does not actually claim to implement the _OLEControl interface). It has five methods, all of which take no arguments and return no result: Activate, Copy, Cut, Delete, and Select. It also exposes Single read-write properties Top, Left, Height, and Width, String properties Name and AltHTML, and an Automation property of type Object. Excel's extender implements the properties, methods, and events of the _OLEObject interface that can be found in the Excel PIA.

When you drop a button onto a document or worksheet, the project system adds a new field to the host item class but types it as Microsoft .Office.Tools.Word.Controls.Button or Microsoft.Office.Tools .Excel.Controls.Button, respectively. Because the underlying System.Windows.Forms.Button class is extensible, this time, the aggregate actually is a subclass of the Windows Forms control. It still must aggregate the unmanaged extender interface provided by Word or Excel, however.

As a further convenience, the managed objects representing embedded Windows Forms controls also have read-only Right and Bottom properties aggregated onto them.

The "Tag" Field

Every host item and host control now has a field called Tag, which can be set to any value. This field is entirely for you to use as you see fit; it is neither read nor written by any code other than your customization code. It is included because it is very common for developers to have auxiliary data associated with a particular control, but no field on the control itself in which to store the data. Having the object keep track of its own auxiliary data is, in many cases, more straightforward than building an external table mapping controls onto data.

Event Model Improvements

Like VBA, VSTO encourages an event-driven programming style. In traditional VBA programming, relatively few of the objects source events, which can make writing event-driven code cumbersome. In Word, for example, the only way to detect when the user double-clicks a bookmark using the standard VBA object model is to declare an "events" class module with a member referring to the application:

Public WithEvents WordApp As Word.Application 


Then sink the event and detect whether the clicked range overlaps the bookmark:

Private Sub App_WindowBeforeDoubleClick(ByVal Sel As Selection, _   Cancel As Boolean)   If Sel.Range.InRange(ThisDocument.Bookmarks(1).Range) Then     MsgBox "Customer Clicked"   End If End Sub 


And initialize the event module:

Dim WordEvents As New WordEventsModule Sub InitializeEventHandlers   Set WordEvents.WordApp = Word.Application End Sub 


Then add code that calls the initialization method. In short, this process requires a fair amount of work to detect when an application-level event refers to a specific document or control. The VSTO extensions to the Word and Excel object models were designed to mitigate difficulties in some tasks, such as sinking events on specific controls. In VSTO, the bookmark object itself sources events, so you can start listening to it as you would sink any other event.

In Chapter 2, "Introduction to Office Solutions," you saw some of the new VSTO extensions to the view object model in action. You also read about events added by VSTO in Chapter 4, "Working with Excel Events," and Chapter 7, "Working with Word Events." At the end of this chapter, we describe all the additions to the event model in detail.




Visual Studio Tools for Office(c) Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath
Visual Studio Tools for Office: Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath
ISBN: 0321411757
EAN: 2147483647
Year: N/A
Pages: 221

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net