Visual Studio Tools for Office: Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath

Let's start by creating a class that implements ISmartTagRecognizer. Our class will be similar to the class we created in Listing 16.7 and will recognize part numbers in a document. In the newly created project, there is already a class created for you, called Class1, in a file called Class1.vb. Add a Imports SmartTag = Microsoft.Office.Interop.SmartTag line to the Imports statements at the top of the class to bring the SmartTag interfaces into a namespace called SmartTag. Rename Class1 to be a class called Recognizer, and declare the class to implement SmartTag.ISmartTagRecognizer. The class now looks like this:

Imports System.Collections.Generic Imports System.Text Imports SmartTag = Microsoft.Office.Interop.SmartTag Public Class Recognizer Implements SmartTag.ISmartTagRecognizer End Class

Visual Studio provides a neat trick for implementing the ISmartTagRecognizer interface. After you type the line Implements SmartTag.ISmartTagRecognizer, when you press the Enter key at the end of the line Visual Studio automatically creates an initial implementation of the ISmartTagRecognizer interface, as shown in Listing 16.8.

Listing 16.8. An Initial Stub Implementation of a Smart Tag Recognizer Class

using System; Imports System.Collections.Generic Imports System.Text Imports SmartTag = Microsoft.Office.Interop.SmartTag Public Class Recognizer Implements SmartTag.ISmartTagRecognizer Public ReadOnly Property Desc( _ ByVal LocaleID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.Desc Get End Get End Property Public ReadOnly Property Name( _ ByVal LocaleID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.Name Get End Get End Property Public ReadOnly Property ProgId() As String _ Implements SmartTag.ISmartTagRecognizer.ProgId Get End Get End Property Public Sub Recognize(ByVal Text As String, _ ByVal DataType As SmartTag.IF_TYPE, _ ByVal LocaleID As Integer, _ ByVal RecognizerSite As SmartTag.ISmartTagRecognizerSite) _ Implements SmartTag.ISmartTagRecognizer.Recognize End Sub Public ReadOnly Property SmartTagCount() As Integer _ Implements SmartTag.ISmartTagRecognizer.SmartTagCount Get End Get End Property Public ReadOnly Property SmartTagDownloadURL(_ ByVal SmartTagID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.SmartTagDownloadURL Get End Get End Property Public ReadOnly Property SmartTagName( _ ByVal SmartTagID As Integer) _ As String _ Implements SmartTag.ISmartTagRecognizer.SmartTagName Get End Get End Property End Class

We must implement six properties (ProgID, SmartTagCount, Desc, Name, SmartTagDownloadURL, and SmartTagName) and one method (Recognize). Let's start by implementing the properties.

The ProgID property is required only for COM Smart Tags. For our Smart Tag, we will return Nothing.

Public ReadOnly Property ProgId() As String _ Implements SmartTag.ISmartTagRecognizer.ProgId Get Return Nothing End Get End Property

Now let's implement the SmartTagCount property. Normally, this property should return the Integer value 1. This property does not affect how many terms our recognizer can recognize; it affects only how many unique recognizers our Smart Tag recognizer class provides. For simplicity, it usually is easiest to have one Smart Tag recognizer class expose one unique recognizer:

Public ReadOnly Property SmartTagCount() As Integer _ Implements SmartTag.ISmartTagRecognizer.SmartTagCount Get Return 1 End Get End Property

The Desc property takes a locale ID as an Integer and returns a String representing the description of the Smart Tag recognizer. You can use the locale ID to provide localized descriptions, if you want to. For our purposes, the code will return a simple description String for all locales:

Public ReadOnly Property Desc( _ ByVal LocaleID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.Desc Get Return "Recognizes Part Numbers in PN#### format." End Get End Property

The Name property takes a locale ID as an Integer and returns a String representing the name of the Smart Tag recognizer. When the Smart Tag is listed in an Office dialog box, this name will display in parentheses to the right of the string returned by SmartTagCaption in the Action class. Name should return a string no longer than 30 characters. We'll return the string "English" to indicate to the user that our Smart Tag is not localized into other locales:

Public ReadOnly Property Name( _ ByVal LocaleID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.Name Get Return "English" End Get End Property

The SmartTagDownloadURL property takes a Smart Tag ID as an Integer and returns a URL as a String where Smart Tag actions associated with this recognizer can be downloaded from. For this example, we will be providing the Smart Tag action class in the same DLL, so we will always return Nothing.

Public ReadOnly Property SmartTagDownloadURL( _ ByVal SmartTagID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.SmartTagDownloadURL Get Return Nothing End Get End Property

This is the first property we have seen that is passed a smartTagID as a parameter. A Smart Tag ID is an Integer value that for this recognizer class will always be passed 1 because the code returns 1 for the SmartTagCount property. If the code returned some other number for SmartTagCountsay, 5all methods that are passed a Smart Tag ID parameter in the recognizer class would be called five times, once with smartTagID set to 1, then 2, then 3, and so on. This lets one Smart Tag recognizer class provide multiple Smart Tags recognizers.

The SmartTagName property takes a Smart Tag ID as an Integer and returns a unique identifier as a String for the Smart Tag. The identifier must be in the form namespaceURI#tagname. A valid namespace URI would be something like a company Web site's URL followed by a unique directory for the Smart Tag name. So in our case, we will use the URL http://www.aw-bc.com/VSTO. For the tag name, we will use our Smart Tag namespace PartNumberSmartTag. The critical thing when constructing your Smart Tag name is to make sure that it will be unique and not conflict with Smart Tags released by other companies or by your company:

Public ReadOnly Property SmartTagName( _ ByVal SmartTagID As Integer) _ As String _ Implements SmartTag.ISmartTagRecognizer.SmartTagName Get Return "http://www.aw-bc.com/VSTO#PartNumberSmartTag" End Get End Property

Now we have arrived at the method that does all the work of recognizing text in the document: the Recognize method. The method is passed parameters very similar to those passed to Recognize in Listing 16.7. The text to be looked at by our code is passed in as a String. The locale ID is passed in if our recognizer needs to recognize different text depending on the locale. An instance of the ISmartTagRecognizerSite interface is passed in as well. We will use this interface to associate a property bag with any text we recognize in the document.

Text that is recognized is marked with a property bag. The property bag can be emptybut for this example, we will stick a namevalue pair in the property bag to store a price. When we find some text we recognize, we must create a new property bag using ISmartTagRecognizerSite's GetNewPropertyBag method. This method returns an ISmartTagProperties object. We can use this object to write namevalue pairs into the property bag through ISmartTagProperties Write method that takes a key as a String and a value as a String. For this example, we will generate a property with key of "Price" and value being the price of the part identified by the part number we locate in the document.

To tell Office where recognized text is found, you must call ISmartTagRecognizerSite's CommitSmartTag method. This method takes the Smart Tag name as a String (we just call our existing implementation of SmartTagName to get this), the 1-based start position of the recognized text as an Integer, the length of the text we recognized as an Integer, and the ISmartTagProperties object we created using the GetNewPropertyBag method. This is a little different from the document-level custom class we created in Listing 16.7, where the start position of the recognized text was 0-based.

Listing 16.9 shows the final implementation of our Recognizer class.

Listing 16.9. The Final Implementation of a Smart Tag Recognizer Class

Imports System.Collections.Generic Imports System.Text Imports SmartTag = Microsoft.Office.Interop.SmartTag Public Class Recognizer Implements SmartTag.ISmartTagRecognizer Public ReadOnly Property Desc( _ ByVal LocaleID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.Desc Get Return "Recognizes Part Numbers in PN#### format." End Get End Property Public ReadOnly Property Name( _ ByVal LocaleID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.Name Get Return "English" End Get End Property Public ReadOnly Property ProgId() As String _ Implements SmartTag.ISmartTagRecognizer.ProgId Get Return Nothing End Get End Property Public Sub Recognize(ByVal Text As String, _ ByVal DataType As SmartTag.IF_TYPE, _ ByVal LocaleID As Integer, _ ByVal RecognizerSite As SmartTag.ISmartTagRecognizerSite) _ Implements SmartTag.ISmartTagRecognizer.Recognize Dim textToFind As String = "PN" Const length As Integer = 6 ' Found part numbers will ' always be 6 characters long Dim startIndex As Integer = 0 Dim index As Integer = 0 While Text.IndexOf(textToFind, startIndex) >= 0 index = Text.IndexOf(textToFind, startIndex) If index + length <= Text.Length Then Dim partNumber As String = Text.Substring(index, length) Dim price As String = "" If IsValidPart(partNumber, price) Then Dim props As SmartTag.ISmartTagProperties = _ RecognizerSite.GetNewPropertyBag() props.Write("Price", price) RecognizerSite.CommitSmartTag(SmartTagName(1), _ index + 1, length, props) End If End If startIndex = index + textToFind.Length End While End Sub Public ReadOnly Property SmartTagCount() As Integer _ Implements SmartTag.ISmartTagRecognizer.SmartTagCount Get Return 1 End Get End Property Public ReadOnly Property SmartTagDownloadURL( _ ByVal SmartTagID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.SmartTagDownloadURL Get Return Nothing End Get End Property Public ReadOnly Property SmartTagName( _ ByVal SmartTagID As Integer) As String _ Implements SmartTag.ISmartTagRecognizer.SmartTagName Get Return "http://www.aw-bc.com/VSTO#PartNumberSmartTag" End Get End Property Private Function IsValidPart(ByVal partNumber As String, _ ByRef price As String) As Boolean Dim numericPartNumber As Int32 = 0 Try numericPartNumber = _ Convert.ToInt32(partNumber.Substring(2, 4)) Catch End Try ' Only part numbers greater than 1000 are valid If numericPartNumber > 1000 Then Dim rnd As New Random() price = rnd.Next(100).ToString() Return True End If price = "N/A" Return False End Function End Class

Категории