The Windows Forms Control Hosting Architecture


Typically, the implementation details of a particular technology are interesting to know but not a prerequisite for using a feature. In the case of Windows Forms control hosting on an Office document, it is important to understand how the feature is implemented, because you will be exposed to some implementation details as you create solutions using controls.

The Windows Forms Control Host ActiveX Control

Windows Forms control support in Office 2003 and VSTO is based on the capability of Word and Excel to host ActiveX controls on the document surface. When you add a Windows Forms control to a document, what actually is added is an ActiveX control called the Windows Forms control host. The Windows Forms control host acts as a host for each Windows Forms control added to the document. The Office application thinks that it is just hosting a basic ActiveX control because the Windows Forms control host implements all the necessary ActiveX control interfaces.

When the customization assembly is loaded for the document or spreadsheet, the actual Windows Forms control instance is created in the same application domain and security context as the rest of the customization code. Then these Windows Forms control instances are parented by a special parent Windows Forms control, called the VSTOContainerControl, that derives from UserControl. Then the VSTOContainerControl is sited to the Windows Forms control host ActiveX control. Your controlfor example, a Trade Stock button in a spreadsheetis added as a child of the VSTOContainerControl. Figure 14.11 shows this "sandwich" architecture.

Figure 14.11. The basic hosting architecture for Windows Forms controls on the document.


The fact that an ActiveX control is hosting the Windows Forms control on the document surface does peek through at times. One example is in the Excel design view. When you click a managed control that you have added to the Excel workbook surface, the formula bar shows that it is hosted by an embedded ActiveX control with ProgID "WinForms.Control.Host," as shown in Figure 14.12.

Figure 14.12. Excel shows the ProgID of the underlying ActiveX hosting control.


VSTO Controls Derived from Windows Forms Controls

The fact that an ActiveX control is hosting the Windows Forms control dragged onto the document surface does not show up immediately in your code. VSTO adds a member variable to the ThisDocument or Sheet1 class, named something like Button1, that you can code against just as you would if you were working with a traditional Windows Forms form. At first glance, the experience appears to be identical to working with a Windows Forms form, but the type of the control that you added to the document is not quite what you would expect. If you drag a button from the Windows Forms toolbox, it would be natural to expect the type of the button created on the document to be System.Windows.Forms.Button. When you add a button to a spreadsheet, however, VSTO creates a button with type Microsoft.Office.Tools.Excel.Controls.Button that derives from System .Windows.Forms.Button. When you add a button to a Word document, VSTO creates a button with type Microsoft.Office.Tools.Word.Controls .Button that derives from System.Windows.Forms.Button. Understanding why a button in VSTO derives from the standard Windows Forms button requires some further digging into the details of how Windows Forms controls are hosted in a Word or Excel document.

Windows Forms controls, be they controls in the System.Windows.Forms namespace or custom controls written by a third party or you, were originally designed to be added to a Windows Forms form and not an Office document. Luckily, much of the Windows Forms control works just fine when used in an Office document. The main special case is around the positioning of the control. If you set the Left property of a Windows Forms control hosted in a form, it sets the distance in pixels between the left edge of the control and the left edge of its container's client area. This works fine in a form or a container control but does not work well when the control is placed in a document or spreadsheet.

The reason why it does not work well is directly related to the hosting architecture of controls in the document, because the control is actually hosted by the VSTOContainerControl, which is hosted by the ActiveX control. As a result, if VSTO were to expose the raw positioning properties of the control, they would be relative to the area of the VSTOContainerControl container, not the document. Setting the Left property of a control should actually move the ActiveX control within the document, rather than the hosted Windows Forms control within the VSTOContainerControl.

Listing 14.3 illustrates this point. In Listing 14.3, we have a spreadsheet to which we have added some Windows Forms buttons, as shown in Figure 14.1. The Refresh button shown in Figure 14.1 is added to Sheet1 as a member variable called refreshButton of type Microsoft.Office.Tools.Excel.Controls.Button. We display that type in the Startup event. As mentioned earlier, Microsoft.Office.Tools.Excel.Controls .Button derives from System.Windows.Forms.Button. The Microsoft .Office.Tools.Excel.Controls.Button's override of Left sets the position of the ActiveX control hosting the Windows Forms control. The code in Listing 14.3 sets this Left to 0, which causes the control to move to the left edge of the worksheet. Casting refreshButton to a System.Windows.Forms.Button strips the override that VSTO adds for the Left property. Setting the Left property on refreshButton when cast to a System.Windows.Forms.Button sets the Left property of the control relative to the parent VSTOContainerControl. This listing, when run, gives the strange result shown in Figure 14.13, where the first call to Left moved the ActiveX control to the far-left edge of the worksheet, but the subsequent calls to Left and Top on the base class System.Windows.Forms.Button moved the managed control relative to the VSTOContainerControl.

Listing 14.3. A VSTO Excel Customization That Exposes the Windows Forms Control Hosting Architecture

Public Class Sheet1   Private Sub Sheet1_Startup(ByVal sender As Object, _     ByVal e As System.EventArgs) Handles Me.Startup     MsgBox(refreshButton.GetType().ToString())     ' Cast to a System.Windows.Forms.Button     ' to set position on underived control     Dim refreshButtonBase As Button = refreshButton     MsgBox(refreshButtonBase.Parent.GetType().ToString())     MsgBox( _       refreshButtonBase.Parent.GetType().BaseType.ToString())     ' Moving the control on Microsoft.Office.Tools.Button     refreshButton.Left = 0     ' Moving the control again on the base     ' System.Windows.Forms.Button     refreshButtonBase.Left = 10     refreshButtonBase.Top = 10   End Sub End Class 


Figure 14.13. The result of running Listing 14.3. The Refresh button has been offset relative to the VSTOContainerControl in the VSTO hosting architecture.


To enable your code to set the position of the control relative to the document, VSTO creates a derived class for each control that extends the class of the original Windows Forms control and overrides the positional information with the positional information from the ActiveX control in the Office document. The object model object for Excel that provides the properties and methods to position the ActiveX control is called OLEObject, and for Word, it is called OLEControl. The derived classes created for each VSTO Windows Forms control effectively merges the original Windows Forms control class and the OLEObject object for Excel or the OLEControl object for Word.

If you create a Windows Forms control of your own or use a third-party control, when you drag and drop the control to a document or spreadsheet, VSTO automatically generates an extended class for you that merges your control with OLEObject or OLEControl. Because the ability to add custom Windows Forms controls to a document requires the control to be extended, you can use only controls that are not sealed. The good news is that the vast majority of third-party controls are unsealed.

Security Implications of the VSTO Control Hosting Model

The security-minded might be wondering about the implications of having to use an ActiveX control to host managed controls added to a document. This is something that we spent considerable time on to ensure that the ActiveX control did not provide a vulnerability to Office. The Windows Forms control host ActiveX control, when initialized, does not actually do anything and will not run any code until it is accessed by the customization assembly. This means that the control is safe for initialization, and the only way for it to do anything is for code with full trust (the customization) to call it. The control is marked safe for initialization to ensure that it will load in Office with the default security settings.

One strange side effect of the control hosting architecture is that Office requires VBA to be installed to add ActiveX controls to a document. Adding ActiveX controls to a document does not add VBA code to that document, but it does require the use of parts of the VBA engine. Therefore, you need to ensure that your Office installation has VBA installed to use managed controls in the document. VBA is installed by default in all versions of Office, so it is unusual for it not to be installed. VSTO also requires that the Trust Access to Visual Basic Project check box be checked in the Macro Security dialog box of Office on a development machine. This check box does not have to be checked on end-user machines unless you are adding dynamic worksheets at runtime, as described in Chapter 13, "The VSTO Programming Model."

The macro security level in VBA can affect the loading of ActiveX controls and, hence, managed controls. If your user sets the VBA macro security settings to Very High (it is set to High by default), any ActiveX controls in the document will be allowed to load only in their inactive design mode state. In this state, Windows Forms controls in the document will not function properly. Luckily, the default macro security setting of High allows controls to be loaded, assuming that they are safe for initialization. Because all Windows Forms controls in the document are loaded by the Windows Forms control host ActiveX control, which is marked as safe for initialization, all managed controls can load in the High setting.

Limitations of the Control Hosting Model

Each Windows Forms control on the document is contained by an instance of the Windows Forms control host ActiveX control, which leads to some limitations. The most noticeable limitation that affects all controls is the lack of support for a control's TabIndex property. Tab order in a Windows Forms is determined by the containing form or control. This is not a problem with a traditional Windows Forms form because all controls on the form are contained by one container. In VSTO, each control placed onto a document or spreadsheet is contained by it is own containerby its own unique instance of the Windows Forms control host. The net result is that the tab index of the control is scoped to its container, and because there is a one-to-one relationship between control and container, the TabIndex property is of little use. This can have an impact on the accessibility of your application, because users would expect to be able to tab between fields, but nothing happens when they press the Tab key.

Another limitation is that controls such as radio buttons really require the control be contained within a container to make the controls mutually exclusive so that only one radio button within the container can be selected at a time. Without a common container, the radio button is not particularly useful. Adding each radio button directly onto a document or spreadsheet causes each radio button to be hosted in its own container. There is a simple way to work around this problem, however; you just create a user control that has a container (a group box, for example) and then add the radio buttons to the group box within the user control. Then you can add the user control to the document as a single control.

Control State Not Saved

We considered this limitation briefly in the introduction of this chapterthe limitation that the state of a Windows Forms control is not saved in the document. To illustrate, imagine a solution that generates customer-service letters in Word. One of the key pieces of information in the document is the date the customer first called customer service. To aid with entering this date, the Word document contains a DateTimePicker, as shown in Figure 14.14.

Figure 14.14. A DateTimePicker control in a Word document.


This is great functionality for your users, but where will the date that the user picks with the DateTimePicker be stored in the document? Consider the scenario where the user opens the document for the first time. The DateTimePicker defaults to show today's date. Then the user picks a different date, using the DateTimePicker, and saves the document. Now we have a problem: Windows Forms controls placed in a document do not save their state into the document when the document is saved. The next time the document is opened, the DateTimePicker will show today's date again, rather than the date picked by the user the last time the document was saved.

To get the DateTimePicker to remember the date picked by the user the last time the document was saved, you have to write code to detect when the user picks a new date by handling the DateTimePicker control's ValueChanged event. You need to store the date in the document somehow so that it will be saved when the document is saved. Some options you have for storing the date that was picked include inserting some hidden text into the document, adding a custom property to the document, or using the cached-data feature of VSTO to cache the date in the data island of the document. Then you have to write some code in the Startup event handler to set DateTimePicker.Value to the saved date.

Listing 14.4 shows some VSTO code associated with the Word document shown in Figure 14.14. The code uses the cached-data feature of VSTO, described in Chapter 18, "Server Data Scenarios," to save the date that was picked in the DateTimePicker in a public field called lastPickedDate that has been marked with the Cached attribute. The Cached attribute causes the value of lastPickedDate to be saved automatically in a data island in the document from session to session. The Startup handler puts the stored value of lastPickedDate back in the DateTimePicker each time the document is reopened.

Listing 14.4. A VSTO Word Customization That Saves the Date That Was Picked Using the Cached-Data Feature of VSTO

Public Class Sheet1   <Cached()> _   Public lastPickedDate As DateTime = DateTime.MinValue   Private Sub Sheet1_Startup(ByVal sender As Object, _     ByVal e As System.EventArgs) Handles Me.Startup     If lastPickedDate <> DateTime.MinValue Then       Me.DateTimePicker1.Value = lastPickedDate     End If   End Sub   Private Sub DateTimePicker1_ValueChanged( _     ByVal sender As System.Object, ByVal e As System.EventArgs) _     Handles DateTimePicker1.ValueChanged     lastPickedDate = DateTimePicker1.Value   End Sub End Class 


Controls Sometimes Blurry

Have you noticed that sometimes a control in Word or Excel looks a little blurred when you are in the designer, but it snaps back into focus when you run the project? This is because the Windows Forms control host ActiveX control stores a bitmap of the hosted Windows Forms control so that when Excel or Word first opens the document, it can display the bitmap until the actual control is loaded. This was done because the actual control is not loaded until the customization assembly is fully loaded. If we had not done this, the control would have an attractive red x through it until the customization assembly loaded.

The reason it looks a bit out of focus is that Office antialiases the image when it stores it, so it is not an exact copy of the original bitmap. So if you see a slightly out-of-focus control on your document, you know that your customization assembly has not loaded yet, that it did not load properly, or that you have been up too late writing a book about Windows Forms controls on Office documents!




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