Programming Office Business Applications (OBA) with VSTO is an extreme -you are don’t ever know, which COM wrappers are realized and work good, and which are not. I have some experience with Bookmark control (included in VSTO 3.0 SP1), which is confirm it :)
I need to do anything in Word 2007 like Intellisense in Visual Studio. User types a few symbols, and Word show the list of variants, which contains in the internal reference book of my app. But small search at MSDN forums help me understand, that it’s impossible with VSTO.
Then I simplify the task – user click to some parts of document, afterwards select the value from WinForms control, hosted in CustomTaskPane. But how to identify theese “parts”?
Because I want to give my users possibility of making custom templates, I decide to use bookmark for marking parts of text in the document. In the VSTO runtime Word bookmarks present as interface Microsoft.Office.Interop.Word.Bookmark and class Microsoft.Office.Tools.Word.Bookmark. Class is more useful, because it bring powerful object model, contains many properties,which allow to customize style of text. And then logic of application is follow: add-in look all created and opened documents for our predefined bookmarks, hook it Selected and Deselected events and open or close TaskPane in the handlers.
But when I open more than one document, NullReferenceException is thrown (details here), and reasons of this behavior is not defined. Then I scan document for predefined bookmark names and insert ContentControl into marked place. Inside ContentControlOnEnter and ContentControlOnExit I switch CustomTaskPane to visible or not.
Few steps you need to do it:
1) Handle WindowActivate and DocumentBeforeClose on start and cancel handling on stop:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
foreach (Window wnd in Application.Windows)
{
Application_WindowActivate(wnd.Document, wnd);
}
Application.WindowActivate += Application_WindowActivate;
Application.DocumentBeforeClose += Application_DocumentBeforeClose;
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
Application.WindowActivate -= Application_WindowActivate;
Application.DocumentBeforeClose -= Application_DocumentBeforeClose;
}
2) Analyze content of the document, and insert ContentControl and handle appropriate events:
bool Check(Document Doc)
{
bool isOurControlsPresent = false;
if (Doc.Bookmarks.Count > 0)
{
foreach (Bookmark bookmark in Doc.Bookmarks)
{
if (BkmIds.Ids.Contains(bookmark.Name))
{
if (Doc.ContentControls.Cast<ContentControl>().Where(c => c.Tag == bookmark.Name).Count() == 0)
{
Object rg = bookmark.Range;
Word.ContentControl ct =
Doc.ContentControls.Add(WdContentControlType.wdContentControlRichText, ref rg);
ct.Tag = bookmark.Name;
}
isOurControlsPresent = true;
}
}
if (isOurControlsPresent)
{
Doc.ContentControlOnEnter += Doc_ContentControlOnEnter;
Doc.ContentControlOnExit += Doc_ContentControlOnExit;
}
}
return isOurControlsPresent;
}
3) Inside OnEnter and OnExit handlers show and hide CustomTaskPane by calling method:
private void SwitchTackPaneVisibility(bool visible)
{
foreach (CustomTaskPane taskPane in CustomTaskPanes)
{
if ((taskPane != null) && (taskPane.Control is DataTaskPane))
{
taskPane.Visible = visible;
}
}
}
That’s all. Some screenshots. When I open my document, I have following:

When mouse pointer over marked words:

When I click on any of words (“first” or “second”) CastomTaskPane is shown:

And when I click on the button, data is added to marked by bookmark place in document:
