New in Word 2007, content controls can be inserted into a document to provide more structure and control—for example when you have a section of the document that you want to allow the user to put a picture into or pick a value from a drop-down list. There are eight content controls: rich text, plain text, picture, combo box, drop-down list, date picker, group, and building block gallery. These controls can be found in the Developer tab of Word’s Ribbon. The developer tab isn’t displayed by default in Word—to display it, choose Word Options from the Office menu, then select Show Developer tab in the Ribbon from the Popular tab of the Word Options dialog. Here is the Controls group in the Developer tab of the Ribbon:

figure7_11

Shown below is the result of inserting a rich text control into a blank document. When the rich text control is selected as it has been below, the control displays with a border UI to which you can add a title to identify the control. When the control is deselected, it displays without the border UI and optional title and just looks like any other region of text in the document. This is important as it allows you to have a control paradigm in the document but only while the user is editing the contents of the control—when the user reads or prints the document, no control border UI is displayed.

figure7_12

Lets examine the events that can be raised on content controls.

Document.ContentControlAfterAdd is raised after a content control is added to the document. Word passes the ContentControl object for the newly added content control as a parameter to this event. It also passes an inUndoRedo bool parameter that indicates whether the content control was added because undo or redo was invoked.

Document.ContentControlBeforeDelete is raised before a content control is deleted from the document. Word passes the ContentControl object for the content control that is about to be deleted as a parameter to this event. It also passes an inUndoRedo bool parameter that indicates whether the content control was deleted because undo or redo was invoked.

Document.ContentControlOnExit is raised when a user leaves a content control that currently has focus and sets the focus to another part of the document. Word passes the ContentControl object for the content control that lost focus as a parameter to this event. It also passes by reference a bool cancel parameter. The cancel parameter can be set to true by your event handler to prevent the user from leaving the content control.

Document.ContentControlOnEnter is raised when a user enters a content control by setting the focus to the content control. Word passes the ContentControl object for the content control that gained focus as a parameter to this event.

Document.ContentControlBeforeStoreUpdate is raised when a content control that is bound to a CustomXMLPart in the document (using the XMLMapping property) has an update to pass to the XML data store. Word passes the ContentControl object for the content control that is about to update the CustomXMLPart. It also passes by reference a string content parameter. The content parameter can be modified by your event handler to change the data before it is put in the CustomXMLPart.

Document.ContentControlBeforeContentUpdate is raised when a content control that is bound to a CustomXMLPart in the document (using the XMLMapping property) is updated from the CustomXMLPart. Word passes the ContentControl object for the content control that is about to be updated from the CustomXMLPart. It also passes by reference a string content parameter. The content parameter can be modified by your event handler to change the data coming from the CustomXMLPart before it updates the bound content control.

Document.BuildingBlockInsert is raised when a building block (a block of pre-defined content in a Word template that can include text, images, etc) is added to the document. Word passes the Range object for where the building block is inserted in the document as a parameter to this event. Word passes the name of the building block in the string name parameter, the category of the building block in the string category parameter, the type of the building block in the string type parameter, and the name of the template that contains the building block in the string template parameter.

The code below shows a VSTO Word document customization that handles the content control related events. To see all these event handlers work, add the code to a document and while running the document, add content controls to the document by clicking on the control icons in the Controls group in the Developer tab.

public partial class ThisDocument
{
  private void ThisDocument_Startup(object sender, 
    System.EventArgs e)
  {
  }
 
  private void ThisDocument_Shutdown(object sender,
    System.EventArgs e)
  {
  }
 
  #region VSTO Designer generated code
  private void InternalStartup()
  {
    this.ContentControlBeforeStoreUpdate +=
      new Word.DocumentEvents2_ContentControlBeforeStoreUpdateEventHandler(
        this.ThisDocument_ContentControlBeforeStoreUpdate);
 
    this.BuildingBlockInsert +=
      new Word.DocumentEvents2_BuildingBlockInsertEventHandler(
        this.ThisDocument_BuildingBlockInsert);
 
    this.ContentControlAfterAdd +=
      new Word.DocumentEvents2_ContentControlAfterAddEventHandler(
        this.ThisDocument_ContentControlAfterAdd);
 
    this.ContentControlOnEnter +=
      new Word.DocumentEvents2_ContentControlOnEnterEventHandler(
        this.ThisDocument_ContentControlOnEnter);
 
    this.Shutdown += new System.EventHandler(this.ThisDocument_Shutdown);
 
    this.ContentControlOnExit +=
      new Word.DocumentEvents2_ContentControlOnExitEventHandler(
        this.ThisDocument_ContentControlOnExit);
 
    this.ContentControlBeforeDelete +=
      new Word.DocumentEvents2_ContentControlBeforeDeleteEventHandler(
        this.ThisDocument_ContentControlBeforeDelete);
 
    this.Startup += new System.EventHandler(this.ThisDocument_Startup);
 
    this.ContentControlBeforeContentUpdate +=
      new Word.DocumentEvents2_ContentControlBeforeContentUpdateEventHandler(
        this.ThisDocument_ContentControlBeforeContentUpdate);
  }
  #endregion
 
  private void ThisDocument_ContentControlAfterAdd(
    Word.ContentControl newContentControl,
    bool inUndoRedo)
  {
    MessageBox.Show(String.Format(
      "ContentControl of type {0} with ID {1} added." +
      "  inUndoRedo is {2}.",
      newContentControl.Type, newContentControl.ID, inUndoRedo));
  }
 
  private void ThisDocument_ContentControlBeforeContentUpdate(
    Word.ContentControl contentControl,
    ref string content)
  {
    MessageBox.Show(String.Format(
      "ContentControl of type {0} with ID {1} updated." +
      "  New content is {2}.",
      contentControl.Type, contentControl.ID, content));
  }
 
  private void ThisDocument_ContentControlBeforeDelete(
    Word.ContentControl oldContentControl,
    bool inUndoRedo)
  {
    MessageBox.Show(String.Format(
      "ContentControl of type {0} with ID {1} deleted." +
      "  inUndoRedo is {2}.",
      oldContentControl.Type, oldContentControl.ID, inUndoRedo));
  }
 
  private void ThisDocument_ContentControlBeforeStoreUpdate(
    Word.ContentControl contentControl,
    ref string content)
  {
    MessageBox.Show(String.Format(
      "ContentControl of type {0} with ID {1} updating " + 
      "XML Store with content {2}.",
      contentControl.Type, contentControl.ID, content));
  }
 
  private void ThisDocument_ContentControlOnEnter(
    Word.ContentControl contentControl)
  {
    MessageBox.Show(String.Format(
      "ContentControl of type {0} with ID {1} entered.",
      contentControl.Type, contentControl.ID));
  }
 
  private void ThisDocument_ContentControlOnExit(
    Word.ContentControl contentControl,
    ref bool cancel)
  {
    MessageBox.Show(String.Format(
      "ContentControl of type {0} with ID {1} exited.",
      contentControl.Type, contentControl.ID));
  }
 
  private void ThisDocument_BuildingBlockInsert(
    Word.Range range, string name,
    string category, string blockType,
    string template)
  {
    MessageBox.Show(String.Format(
      "BuildingBlock added at position {0} with name {1}, " +
      "category {2}, blockType {3}, from template {4}.",
      range.Start, name, category, blockType, template));
  }
}

To see the ContentControlBeforeStoreUpdate and ContentControlBeforeContentUpdate events fire, you need to add a content control that is bound to the XML store in the document. The easiest way to do this is to use the Quick Parts drop down in the Insert tab. From the Quick Parts drop down, add a document property like Author from the Document Property menu. The content control that is added will be mapped to Author in the document properties in the XML data store. When you edit the content control then exit the content control, the ContentControlBeforeStoreUpdate event will be raised as the contents of the content control get written back to the Author property in the XML data store. To see the ContentControlBeforeContentUpdate event fire, use the Office menu, pick Prepare, then Properties. The document properties will be shown in the document information pane. Edit the author field in the document properties pane then exit the author field. This will cause the ContentControlBeforeContentUpdate event to be raised as the change you made in the document information pane is pushed from the XML data store back to the bound content control in the document. The picture below shows a Word document with a content control bound to the Author property in the XML data store. It also shows the document information pane where the Author property is displayed directly out of the XML data store.

Finally, to see the BuildingBlockInsert event, use the Quick Parts drop down in the Insert tab and select Building Blocks Organizer. From the Building Block Organizer dialog, pick a building block to insert and click on the Insert button.

figure7_13

From the book “Visual Studio Tools for Office 2007”