Dynamic Controls

In Chapter 2, you saw that VSTO allows developers to build customized document solutions by using Word and Excel as designers inside Visual Studio. The host item classes expose the host controls present at design time as custom properties on a class that aggregates the underlying unmanaged object.

But what about host controls not present at design time? What if you want to create new named ranges, bookmarks, buttons, or other controls at runtime? It would be nice to be able to use the new events and other extensions to the programming model on dynamically generated controls. As you will see, VSTO supports dynamically adding both host items and host controls, although the former is a little bit trickier to pull off.

Chapter 14 shows how to dynamically add Windows Forms controls to Word and Excel documents.

The Controls Collection

In a Windows Forms application, every form class has a property called Controls that refers to a collection of all the controls hosted by the form. In VSTO, each worksheet and document class contains a similarly named property; in Word, the document class contains an instance of Microsoft.Office.Tools.Word.- ControlCollection, in Excel each worksheet class contains an instance of Microsoft.Office.Tools.Excel.ControlCollection. They are quite similar; the following sections discuss their differences.

Enumerating and Searching the Collection

You can use the Controls collection to enumerate the set of aggregated controls and perform actions upon all of them. For instance, you could disable all the button controls on a sheet or document:

foreach (object control in this.Controls)
 Button button = control as Button;
 if (button != null)
 button.Enabled = false;

The Controls collection also has some of the indexing and searching methods you would expect. Both the Excel and Word flavors have methods with these signatures:

bool Contains(string name)
bool Contains(object control)
int IndexOf(string name)
int IndexOf(object control)

If the collection does not contain the searched-for control, then IndexOf returns 1. Both collections can be enumerated via the foreach loop; should you want to enumerate the collection yourself, you can call GetEnumerator. This method returns a ControlCollectionEnumerator object from the Microsoft.Office.Tools.Excel or Microsoft.Office.Tools.Word namespace, as appropriate. They are essentially identical functionally. Both classes have only three public methods:

  • object get Current
  • bool MoveNext()
  • void Reset()

Current returns null when moved past the final element in the collection, MoveNext moves the enumerator to the next element, and Reset starts the enumerator over at the beginning of the collection.

Both collections also expose three index operators, which take a name string, int index, and object respectively. The indexers throw an ArgumentOutOfRangeException if there is no such control in the collection.

Adding New Word and Excel Host Controls Dynamically

The worksheet and document Controls collections provide methods to dynamically create host controls. In Word, you can dynamically create aggregated bookmarks:

Microsoft.Office.Tools.Word.Bookmark AddBookmark(
 Microsoft.Office.Interop.Word.Range range, string name)

This method creates a new bookmark on the given range and aggregates it with the VSTO host control class.

XMLNode and XMLNodes host controls cannot be created dynamically in Word. The XMLMappedRange host control cannot be created dynamically in Excel.

In Excel, you can dynamically create aggregated NamedRanges, ListObjects, and Chart controls. Of those, only Chart controls can be positioned at arbitrary coordinates; the rest must all be positioned with a range object:

Microsoft.Office.Tools.Excel.Chart AddChart(
 Microsoft.Office.Interop.Excel.Range range, string name)
Microsoft.Office.Tools.Excel.Chart AddChart(
 double left, double top, double width, double height, string name)
Microsoft.Office.Tools.Excel.NamedRange AddNamedRange(
 Microsoft.Office.Interop.Excel.Range range, string name)
Microsoft.Office.Tools.Excel.ListObject AddListObject(
 Microsoft.Office.Interop.Excel.Range range, string name) 


Removing Controls

The host controls added to a worksheet or document host item class at design time are exposed as properties on the host item class. If at runtime the user were to accidentally delete one, save the document, and then reload it, the customization code would be unable to find the aggregated control. This would likely result in an exception because eventually the customization would try to listen to an event or call a method on the missing aggregated control. If the customization detects this condition, it will throw a ControlNotFoundException.

Although it is difficult to prevent end users from accidentally or deliberately deleting controls without locking the document, the Controls collection can at least try to prevent programmatic destruction of controls added at design time. There are four equivalent ways to remove controls from the Controls collection; all will throw a CannotRemoveControlException if you attempt to remove a control that was not added dynamically.

The four ways to remove a dynamic control are to call Delete() on the control itself, or to call Remove(object control), Remove(string name), or RemoveAt(int index) on the Controls collection itself. All four of these remove the control from the collection, remove the control from the document or worksheet, and destroy the extender object.

Most collections have a Clear() method that removes every member from the collection. Because completely clearing a Controls collection would almost always result in an exception when a design-time control was removed, this method always throws a NotSupportedException, and is hidden from IntelliSense.

Dynamic Controls Information Is Not Persisted

What happens when you add one or more dynamic controls to a document, save it, and reload it later?

Dynamically created Windows Forms controls such as buttons and check boxes do not survive being saved and then loaded. They just disappear; your customization code can create them again afresh the next time the document is loaded.

Because "host" controls such as ranges and bookmarks are themselves part of the document, they will be persisted along with the rest of the document. However, the controls do not save any information about any aggregating objects you may have created around them. When the document is reloaded, the controls will still be there, but there will be no aggregates wrapping them. You will have to re-add the controls to the Controls collection to create new aggregates for the controls. The Controls collection provides Add methods that can reconnect an aggregate to an existing control in the document without creating a new control in the document.

Visual Studio Tools for Office(c) Using C# with Excel, Word, Outlook, and InfoPath
Visual Studio Tools for Office(c) Using C# with Excel, Word, Outlook, and InfoPath
ISBN: 321334884
Year: N/A
Pages: 214
Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net