Writing Code Behind Events

If you've written any Microsoft® Visual Basic® code, you've almost certainly written event procedures. An event procedure contains code that is executed when an event occurs. For example, a Visual Basic form with a button can have a procedure to handle the button's Click event. And writing code behind events in the Microsoft® Visual Basic® for Applications (VBA) environment in the Visio application is the same as writing code behind events in any other VBA host application; for example, any Microsoft® Office application.

Every VBA project in Visio is set up to capture the events raised by the Document object associated with the project (ThisDocument). To respond to events raised by other Visio objects, you can declare object variables using the WithEvents keyword, which exposes all of the events defined for that particular object type, and provides skeleton event-handling procedures in your project. All you need to do is write code for the events you want to handle.

WithEvents object variables must be declared in class modules. You can declare them in the ThisDocument class, which is a default class module in every Visio VBA project, or you can declare WithEvents object variables in a separate class module that you insert into your project.

Writing code behind events is also a way to handle the events raised by any Microsoft® ActiveX® controls that you have inserted into your project. For details on handling events for an ActiveX control, see Chapter 24, Using ActiveX Controls in a Visio Solution.

Note Writing code behind events using the WithEvents keyword is a VBA and Visual Basic feature only. If you are programming in a different environment, see Visio Event Objects later in this chapterPart 3, Visio Event objects(DVS_858), or refer to your Component Object Model (COM) documentation for information on implementing interfaces that support COM-connectable objects.

All the information in this section also applies to a stand-alone Visual Basic project with the following exception: You need to set a reference to the Visio type library from your Visual Basic project. (In Visual Basic, click References on the Projects menu, and then select the Microsoft Visio 2002 type library.)

In this section…

Handling Events Fired by ThisDocument

Declaring an Object Variable Using the WithEvents Keyword

Defining a Class to Receive Events

Class Module that Responds to Events: an Example

Handling Events Fired by ThisDocument

Every Visio VBA project contains a ThisDocument class module that responds automatically to the events raised by the Document object associated with your project.

For details about using the Visual Basic Editor, see Chapter 15, Programming Visio with VBA.

To create an event procedure in ThisDocument

  1. Double-click ThisDocument in the Project Explorer, and the code window for your document opens. (If you don't see the Project Explorer in the Visual Basic Editor, click Project Explorer on the View menu.)
  • The list box in the upper-left corner of the
  • Code
  • window is the
  • Object
  • box; the list box in the upper-right corner is the
  • Procedure
  • box.
  1. Click Document in the Object box, and the event set for a Document object appears in the Procedure box.
  1. Select an event from the Procedure box, and VBA creates an empty event procedure where you can write code to handle the event. Event procedures are always named object_event.

The ThisDocument code window

The ThisDocument code window

  1. Object box
  1. Code window for ThisDocument with a skeleton procedure
  1. Procedure box

The following example handles two events, DocumentOpened and ShapeAdded, to keep count of shapes (based on a master called Square) that are added to a drawing:

  • The DocumentOpened event handler runs when a new drawing is based on the template that contains this code. The handler initializes an integer variable, intSquares, which is used to store the count.
  • The ShapeAdded event handler runs each time a shape is added to the drawing page, whether the shape is dropped from a stencil, drawn with a drawing tool, or pasted from the Clipboard. The handler checks the Master property of the new Shape object and, if the shape is based on the Square master, increments intSquares.

'Number of squares added to drawing Dim intSquares As Integer Private Sub Document_DocumentOpened(ByVal Doc as IVDocument)     'Initialize number of squares added     intSquares = 0 End Sub Private Sub Document_ShapeAdded(ByVal Shape As IVShape)     Dim mastObj As Master     'Get the Master property of the shape.     Set mastObj = Shape.Master     'Check whether the shape has a master. If not, the shape was created locally.     If Not ( mastObj Is Nothing ) Then         'Check whether the master is "Square".         If mastObj.Name = "Square" Then             'Increment the count for the number of squares added.             intSquares = intSquares + 1         End If     End If     MsgBox "Number of squares: " & intSquares, vbInformation End Sub

To handle events fired by ThisDocument

  1. Open the Visual Basic Editor by clicking the Visual Basic Editor button Aa201789.ic_VBEditor(en-us,office.10).gif on the Developer toolbar. Or, on the Tools menu, point to Macros, and then click Visual Basic Editor.
  1. In the Project Explorer, double-click ThisDocument to open its Code window.
  1. Click Document in the Object box, and the events that get fired by a document will appear in the Procedure box.
  1. Click the event you want to handle; Visio creates an empty event procedure for that event.
  1. Fill in the event procedure with the code you want to execute when the event occurs.

TOP

Declaring an Object Variable Using the WithEvents Keyword

To handle events raised by Visio objects other than your project's document, you can use the VBA keyword WithEvents to declare an object variable for the Visio object whose events you want to handle. The following example describes setting up an object variable to handle the events raised by a Page object.

In ThisDocument, you declare an object variable using the WithEvents keyword and a Visio object type:

Dim WithEvents pageObj As Visio.Page

In addition to the usual access to an object's properties and methods, using the keyword WithEvents in this declaration gives the object variable the capacity to handle events fired by the Page object assigned to that variable. All events in the object's event set will be fired, and you provide code for the events that you want to handle.

By declaring this WithEvents variable as type Visio.Page, VBA can identify the type library (Visio) and the event set (Page) that it needs to capture. Now when you select pageObj in the Object box in the Visual Basic Editor, the Procedure box shows the events that are fired by the Page object.

For example, the following event procedure prints the names of shapes in the Immediate window whenever a shape is deleted from the active page of your project, which is represented by pageObj:

Public Sub pageObj_BeforeShapeDelete (ByVal Shape As IVShape)     Debug.Print Shape.Name End Sub

Before this procedure will run, however, you must connect the declared object (pageObj) with an instance of the object. Because this connection must be made before the BeforeShapeDelete event fires, you might put this statement in an event procedure for an event that you know will execute before BeforeShapeDelete, such as the document's DocumentOpened event. For example**:**

Private Sub Document_DocumentOpened(ByVal doc As IVDocument)     Set pageObj = ActivePage End Sub

When you are finished with an object reference it is a good practice to release the variable reference. This is often done in the BeforeDocumentClose event handler. For example:

Private Sub Document_BeforeDocumentClose(ByVal doc As IVDocument)     Set pageObj = Nothing End Sub

For details about the WithEvents keyword, see your Visual Basic or VBA documentation.

To declare an object variable WithEvents in ThisDocument

  1. Open the Visual Basic Editor and double-click the ThisDocument object in Project Explorer.
  1. In the Code window, define an object variable using the Visual Basic keyword WithEvents in the General section of the module.
  1. Click the object in the Object box, and the events that get fired by that object will appear in the Procedure box.
  1. Click the event you want to handle; Visio creates an empty event procedure for that event.
  1. Fill in the event procedure with the code you want to execute when the event occurs.
  1. Set the object variable equal to an instance of the object.
  1. Set the variable to Nothing when you're finished.

TOP

Defining a Class to Receive Events

You can streamline the process of handling events fired by a particular kind of Visio object by defining a class that contains your event variables and event-handling code. Writing code behind events in a class module works very much the same way as writing code behind events in ThisDocument. When you use a class module to receive events, however, you must create an instance of your class and connect it to a real object. (The ThisDocument object is instantiated and connected to the Document object associated with your project by default.)

When handling events in a separate class module, you write code in two places, your class module and your program.

  • Your class module contains module-level WithEvents variable declarations, code inside of event procedures (code behind events), and code to bind your variable to Visio objects that fire events.
  • Your program (often ThisDocument) contains module-level variable declarations of your class type, and code that creates and assigns an instance of your class to those variables.

Code in your class module

To add a class to your project, on the Insert menu, click Class Module. You can name this class whatever you want. Place all your event-handling code in this class. Let's say that you want to handle events from a Visio instance in your project—in this case, the source object is an Application object.

  1. In your class module, declare a module-level WithEvents variable using the following statement:

Dim WithEvents appObj As Visio.Application

  1. After this variable is declared, appObj appears in the Object box in your class module, and when you select it, the valid events for that object appear in the Procedure box. Click an event in the Procedure box—an empty procedure is added to the class module, and you can write code behind the event you selected. For example, your solution may collect information about shapes in your drawing that it will process when the NoEventsPending event is fired.
  1. You must associate your WithEvents variable with a real source object. To make the connection between a source object and the WithEvents variable, use the Set statement. The WithEvents variable is often assigned in the Initialize procedure of your class module and set to Nothing in the module's Terminate event.

Set appObj = Application

Code in your program

Your event handler is in place, but nothing will happen until you define and create an instance of your class.

  1. Add a reference to your class with the following declaration (usually module-level):

Dim MyClass1 As MySinkClass

  1. Create an instance of your class. For example, if we wanted to respond to events fired by the Application object as described in the previous topic, we could create an instance of the class module inside of the document's DocumentOpened event. To create an instance of your class module, use the New keyword:

Set MyClass1 = New MySinkClass

  • When you create an instance of your class, its
  • Initialize
  • event fires and the
  • WithEvents
  • variable is connected with a real object (see step 3 of the procedure in the previous section,
  • Code in your class module
  • ). When you are finished with the instance of your class, release it by setting it to
  • Nothing
  • . This is often done in the
  • BeforeDocumentClose
  • event in your program:

Set MyClass1 = Nothing

  • For details about the
  • New
  • keyword, see your Visual Basic or VBA documentation.

To create a class module in your project to receive events

  1. Insert a class module into your project.
  1. Declare a module-level object variable using the WithEvents keyword inside your class module.
  1. In the class module, click the object variable in the Object box, and the events that can be handled by that variable appear in the Procedure box.
  1. Click the event you want to handle and provide code in the skeleton procedure.
  1. Create an instance of your class module in your program.
  1. Set the WithEvents variable to the source object whose events you want to receive.

TOP

Class Module that Responds to Events: an Example

The following example demonstrates a Visio project that uses a WithEvents variable to monitor events that are happening in a Visio instance. When this project is running, this event handler will display the document and shape name of any shape that is added to any document open in the Visio instance.

The project defines a class called Listener. In the Listener class, do the following:

  • Declare a private WithEvents variable of type Visio.Application.
  • Write code behind the application's ShapeAdded event.
  • Connect the WithEvents variable with an Application object when the Listener class is instantiated. Then, release the connection when the class terminates.

'Code in the Class Module named Listener Dim WithEvents m_app As Visio.Application Private Sub Class_Initialize()     Set m_app = Application End Sub Private Sub Class_Terminate()     Set m_app = Nothing End Sub Private Sub m_app_ShapeAdded(ByVal Shape As IVShape)     Debug.Print Shape.Document.Name; "/"; Shape.Name End Sub

In ThisDocument, do the following:

  • Define a variable of type Listener.
  • Create an instance of Listener when the document enters run mode. Then, release the object when the document enters design mode or the document closes.

'Code in ThisDocument Dim m_listener As Listener Private Sub Document_RunModeEntered(ByVal doc As IVDocument)     Set m_listener = New Listener End Sub Private Sub Document_DesignModeEntered(ByVal doc As IVDocument)     Set m_listener = Nothing End Sub Private Sub Document_BeforeDocumentClose(ByVal doc As IVDocument)     Set m_listener = Nothing End Sub