Techniques - DevSource
DevSource: Microsoft Developer Resource DevSource Home Sponsored by Microsoft Home Add Ons Architecture Languages Techniques Using VS Forums
Home arrow Techniques arrow Page 4 - RibbonX for Dummies: Chapter 6 (Part 2)
RibbonX for Dummies: Chapter 6 (Part 2)
By John Mueller

Rate This Article: Add This Article To:

RibbonX for Dummies: Chapter 6 (Part 2)
( Page 4 of 6 )

Creating the Templates variable and interacting with Word

Many of the callbacks rely on a global variable named Templates that contains a list of the templates for the current user. The example places the code to create this variable in the OnLoad() callback. Here's the code that makes everything else work:

// Obtain the user's path to templates.

string TemplatePath =

Globals.ThisAddIn.GetTemplatePath();

// Build a list of form templates.

Templates = Directory.GetFiles(

TemplatePath + @"\Forms", "*.DOTX");

The code begins by obtaining the location of the templates for the current user. You could use any other location on the hard drive as a starting point, but using the current user's folder ensures that Word can find the templates it needs. All of the forms reside in a special folder named Forms and have a DOTX file extension, so using the GetFiles() method makes it easy to fill the Templates array with a list of template filenames. Of course, the big question is where the Globals.ThisAddIn.GetTemplatePath() method resides.

ADVERTISEMENT

You can't interact directly with Word from the Ribbon1.CS file; all you can do is interact with the Ribbon. Consequently, if you want the add-in to perform any useful work, you must call on public methods in the ThisAddIn class located in ThisAddIn.CS. Unfortunately, you can't access this class directly. If you try to create an instance of the class or create static members, you quickly find that you can't achieve any results, even if the code compiles. You always access the members of the ThisAddIn class using the Globals object as shown. When you type Globals, instantly you see a list of add-ins; after selecting a list of add-ins, you'll see the public members for that add-in. Here, the reason for the special emphasis is that Microsoft isn't particularly good about documenting these interactions — you almost need to know already that they exist, without Microsoft's help. The GetTemplatePath() method simply accesses Word and obtains the current path, as shown here:

public String GetTemplatePath()

{

// Obtain the template path for Word and return it.

return Application.NormalTemplate.Path;

}

Obtaining the template information for display

The remaining attributes define callbacks that Word needs to define the gallery content. Each image requires the getItemID and getItemImage attributes as a minimum (the getItemLabel attribute is optional, as are many of the other callbacks). The code must also implement the getItemCount attribute or the gallery won't know how many templates to display. Finally, you need to implement onAction to provide some means of reacting to user selections. Listing 6-12 shows the code required to implement the callbacks for this part of the example.

Listing 6-12: Providing the Gallery Items

public long GetItemCount(Office.IRibbonControl control)

{

// Return the number of items based on the template

// length.

return Templates.Length;

}

public string GetItemID(Office.IRibbonControl control,

int index)

{

// Obtain the template name.

string ThisID =

Path.GetFileNameWithoutExtension(

Templates[index]);

// Remove any extra spaces.

ThisID = ThisID.Replace(" ", "");

// Return the item id based on the template name.

return ThisID;

}

public Bitmap GetItemImage(

Office.IRibbonControl control, int index)

{

// Obtain a pointer to the current template image.

String TemplateLocation = Templates[index];

TemplateLocation =

TemplateLocation.Replace(".dotx", ".png");

// Create a bitmap based on the image.

Bitmap TemplateImage = new Bitmap(TemplateLocation);

// Return the bitmap.

return TemplateImage;

}

public string GetItemLabel(

Office.IRibbonControl control, int index)

{

// Return the template name.

return

Path.GetFileNameWithoutExtension(

Templates[index]);

}

public void ItemClicked(Office.IRibbonControl control,

string selectedId,

int selectedIndex)

{

// Use this path to supply information for the

// template.

Globals.ThisAddIn.CreateNewDocument(

Templates[selectedIndex]);

}

The GetItemCount() method simply returns the length of a special variable named Templates that contains an array of template path strings. For right now, all you need to know is that the array shows where each template in the list resides. The "Creating the Templates variable and interacting with Word" section of the chapter describes how the application creates this variable. The Templates.Length property tells how many items the array contains, which therefore tells you how many elements the gallery has. Every item in the gallery must have a unique ID. The GetItemID() method provides a unique ID based on the template filename. It's unlikely that two templates will have a name variation so close that it results in an ID collision.

Notice how the code uses the Path.GetFileNameWithoutExtension() method to obtain just the filename, and then takes the spaces out of the filename to produce the ID.

Using the filename approach to creating IDs also makes it easier to debug your application. If a particular template causes problems, you can discover its name quickly and perform any required changes.

Remember that every one of the templates has an associated .PNG file that contains the screenshot of that template. The GetItemImage() method uses this feature to obtain an image for the gallery. The code begins by obtaining a template location, and then replaces the template file extension with the PNG extension. The code can then create a Bitmap for the image and return it to Word. Notice how none of the resources in this example require an absolute directory location — the code automatically compensates for differences in system setup.

The templates for this example have descriptive names; that way they're easier to locate if they require changes. In fact, there's no reason not to give them descriptive names. The GetItemLabel() method uses this template feature to create the labels for each gallery item. You can't count on the user seeing enough of the template to make a choice, so the distinctive name is a requirement to ensure the user makes the right selection at the outset.

The ItemClicked() method provides that last piece of the puzzle. When a user clicks on one of the templates, Word calls this callback with the selected item's ID and index. The code makes a call to the Globals.ThisAddIn. CreateNewDocument() method to actually create a new form, basing the form on the template location provided in the Templates variable. You'll always need to add this extra code because Office doesn't let you access the application directly through the Ribbon callback code.

Creating the new document with a particular template

In many respects, working with Word in Visual Studio looks like merely a different kind of VBA application. Of course, there are differences, but the essential coding tasks are the same. Listing 6-13 shows the code required to create a new form based on one of the templates you created earlier in this example.

Listing 6-13: Creating the new form based on the selected template

public void CreateNewDocument(string ThisTemplate)

{

// Get rid of Document1 if the user has recently

// opened Word and this is the first document

// created.

if (Application.ActiveDocument.Name == "Document1")

{

// Use wdPromptToSaveChanges to ensure the user

// still has a chance to save any changes. The

// prompt won't appear if the user hasn't made

// any changes to Document1.

object SaveChanges =

(object)Word.WdSaveOptions.wdPromptToSaveChanges;

// Save the document in its original format.

object OriginalFormat =

(object)Word.WdOriginalFormat.wdOriginalDocumentFormat;

// Don't route the document anywhere.

object RouteDocument = (object)false;

// Close Document1.

Application.ActiveDocument.Close(

ref SaveChanges, ref OriginalFormat,

ref RouteDocument);

}

// Create the new document.

// Define the template to use to create the

// document.

object objTemplate = (object)ThisTemplate;

// Don't create a new template based on the document

// template.

object objNewTemplate = (object)false;

// Define the kind of document to create.

object objDocumentType =

(object)Word.WdNewDocumentType.wdNewBlankDocument;

// Make sure the document is visible so the user can

// see it.

object objVisible = (object)true;

// Create the document.

Application.Documents.Add(ref objTemplate,

ref objNewTemplate,

ref objDocumentType,

ref objVisible);

}

The code begins by checking for Document1, the default name of the document that appears when you open Word. Notice that the code makes this check without creating any special objects. If you try to type Application and don't see the IntelliSense for the relation objects, you're probably working in the wrong file.

The code begins by creating some variables for the Application.Active Document.Close() method. Unlike VBA, this code won't let you simply skip arguments. You must provide every required argument for the method calls, even if that means supplying a default value.

Most of the calls you'll make refer to the object class — they don't provide much in the way of information about the kind of input the call expects. The example doesn't take any chances with the user's data. If you have any doubt about the data type, look up the method call in the VBA documentation.

Notice how the example uses type coercion to document the values for each argument. The code uses the actual VBA types, but then coerces them to the object type. VB.NET users will find that they need to do less work than C# developers because VB.NET performs some of the type coercion for you. The example calls the Application.ActiveDocument.Close() method using the ref keyword in C#. VB.NET developers don't have to add the extra keyword. The reason you must include this keyword in C# is to allow Word to pass back information (it happens rarely — make sure you understand how the method call works before you assume that Word will provide any return values). Notice that the example uses Word.WdSaveOptions.wdPromptTo SaveChanges to ensure that the user doesn't lose any data. Word won't display a dialog box unless the user has made changes to the document.

Creating the new document comes next. As with the Application. ActiveDocument.Close() method, the Application.Documents. Add() method requires not only that you pass arguments of the object type, but also that you pass them by reference. The objTemplate argument always contains the name of the template you want to create. The remaining arguments define how Word creates the document. You can choose to create the document as a template, to use a document type other than a blank document (such as an e-mail), and even to create invisible documents so you can work in the background.



 
 
>>> More Techniques Articles          >>> More By John Mueller
 



Microsoft's Future: A Chat With Their CTO, Barry Briggs

Play Video >

All Videos >

Julia explores the Robotics Studio!

Read now >

Messages to Bill Gates!

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.