Overview:
This sample is intended to expose several common tasks in
VSTA, including: declaring an object, using and manipulating a form, and handling
form events and event args. This sample
contains a very simple object, form, application with a basic VSTA integration,
and an add-in. An EventHelper is used to
prevent any errors in add-in event handling.
To run the sample, extract the files, open and build the
EventSample solution, then run the setup file included (double click or use the
command “cscript SetupEventSample.js” from a command prompt). Next, open and build the add-in solution
included in the Samples folder. Run the
EventSample application, which should now automatically find and load the sample
add-in included.
The EventSample application records button clicks and input
from a text box in a list box. The
sample add-in responds to mouse clicks on any of the buttons on the form, to adding
input through the add button, clearing the display, and selecting the Open
button. Event handling for the Save and
Close buttons in the add-in is not implemented.
Included in this sample:
|
Item
|
Description
|
|
MainForm
|
Main user form and empty code class.
|
|
Program
|
Starting point in the host
application.
|
|
MainApplication
|
Main application class. All application specific code is here.
|
|
MainObject
|
Main object used by the
MainApplication class. Consists of a
string.
|
|
EventArgs
|
Contains class definitions for
custom event used by the MainApplication.
|
|
EventHelper
|
Class taken from ShapeApp samples
to manage events from the host application and add-ins.
|
|
VstaRunTimeIntegration
|
Class based on the ShapeApp samples
which uses the VSTA pipeline to load and manage add-ins.
|
|
HostItemProvider
|
Class based on the ShapeApp samples
which allows add-ins to access the host object model.
|
|
HostTypeMapProvider
|
HTMP file generated by ProxyGen and
translated into Visual Basic. Maps the
types to canocial names for translation between the host and add-ins.
|
|
EventSampleProxy
|
Proxy file generated by ProxyGen
and updated to allow generic event handling.
|
|
EventSampleProject1
|
A sample add-in that interacts with
the events of the host application.
|
I) Declaring Objects in VSTA
VSTA cannot access constructors from the host application. The constructors included in the proxy file
are for internal use only. To create an
object in VSTA, a public method must be available in the add-in entry point, in
this case the MainApplication class, which constructs the object, then returns
it. The code below shows an object
class, MainObject, the MainApplication class, and an add-in. In the MainApplication class, the method
NewObject is used by the add-in to create a MainObject in the add-in.
''' HOST
''' <summary>
''' Simple
object used by the main application.
''' </summary>
Public Class MainObject
''' <summary>
''' Holds a
message which is displayed on the main form.
''' </summary>
Private
mMessage As String
Public Property Message() As
String
Get
Return
mMessage
End Get
Set(ByVal value As String)
mMessage = value
End Set
End Property
''' <summary>
''' Creates a new
MainObject with the message passed in.
''' </summary>
Public Sub New(ByVal messageIn As String)
Message = messageIn
End Sub
End Class
''' HOST
''' <summary>
''' Main class
of the application.
''' VSTA entry
point.
''' </summary>
Public Class MainApplication
''' <summary>
''' Factory
method used to create a new MainObject.
''' </summary>
''' <remarks>VSTA
requires objects to be created on the host side
''' using a
factory method instead of using the "New" operator</remarks>
Public Function NewObject(ByVal
inMessage As String)
As MainObject
Return New MainObject(inMessage)
End Function
End Class
''' ADD-IN
Private Sub AppAddIn_Startup(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles Me.Startup
'create a new
MainObject
Dim
myObject As MainObject = Me.NewObject("New
MainObject for VSTA add-in")
End Sub
II) Using Forms in VSTA
Forms and other objects under System.Windows.Forms cannot be
passed through the proxy layer because they are not serializable. To include a form, or any
System.Windows.Forms object, make it an internal property in the main
application and exclude the form’s class in the descriptor file. The code below demonstrates how to start a
windows form based application. The
starting point of the host application, the Program class, contains a
MainApplication property. The
MainApplication class contains a MyForm property which is run by the Program
class.
''' HOST
''' <summary>
''' Startup
object of the host application.
''' </summary>Public Class Program
<STAThread()> _
Shared Sub Main()
'prepare to
use forms
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
'create the
application
Dim
thisApplication As MainApplication = New MainApplication()
'run the form
Application.Run(thisApplication.MyForm)
End Sub
End Class
''' HOST
''' <summary>
''' Main class
of the application.
''' VSTA entry
point.
''' </summary>
Public Class MainApplication
''' <summary>
''' Form used
internally only.
''' </summary>
Private
mMyForm As MainForm
Friend ReadOnly Property
MyForm() As MainForm
Get
Return
mMyForm
End Get
End Property
End Class
III) Manipulating a form in VSTA
With the form set as an internal property in the
MainApplication class, VSTA cannot directly interact with the form or its
controls. To interact with these, the
AddInEntryPoint (in this case the MainApplication class) must contain public
methods which handle these interactions.
The code below shows the MainApplication’s addTextToListBox method which
takes in a string and adds it to the list box lstDisplay contained on the
form. The add-in calls this method and
the string passed in from the add-in is displayed in the list box on the form.
''' HOST
''' <summary>
''' Main class
of the host application.
''' VSTA entry
point.
''' </summary>
Public Class MainApplication
Public Sub addTextToListBox(ByVal
message As String)
'display the
message in the list box
MyForm.lstDisplay.Items.Add(message)
End Sub
End Class
''' ADD-IN
Private Sub AppAddIn_Startup(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles Me.Startup
'add a
message to the list box
addTextToListBox("Message from VSTA add-in")
End Sub
IV) Form Events in VSTA
In order for an add-in to catch an event on a form, the host
application must catch the event and fire a public event that VSTA can
see. In the code below, the constructor
of the MainApplication calls the method HookUpEvents which associates a method
in the host application, DisplayClear, with an event generated by the form, a
button click. The method in the host
application hooked up to this form event, DisplayClear, fires the public event,
DisplayClearedEvent, which VSTA can see.
The add-in hooks up a method, AddIn_DisplayClear, with the event and
displays a line of text on the form.
Note: When firing events accessible from VSTA it is
important to use the host application (or object within the host application)
as the sender, by specifying “me” (“this” in C#). Using the original sender will not work.
''' HOST
''' <summary>
''' Main class
of the host application.
''' VSTA entry
point.
''' </summary>
Public Class MainApplication
''' <summary>
''' Prepares the
host application to run.
''' Sets up the
list of objects and the form.
''' Hooks up form
events to methods that will raise VSTA visible events.
''' </summary>
Public Sub New()
'instantiate
the form and lis tof messages
mMyForm = New
MainForm
mMyObjects = New
List(Of MainObject)
'hook up the
event handling to the form
HookUpEvents()
End Sub
''' <summary>
''' Event raised
when the display is cleared
''' </summary>
Public Event DisplayClearedEvent As
EventHandler
''' <summary>
''' Associates
form events with methods that will raise
'''
VSTA visible events.
''' </summary>
Private Sub HookUpEvents()
'Event
handling for the form, not exposed to VSTA
' VSTA accessable events are raised in the methods
hooked into
AddHandler
MyForm.cmdClear.Click, AddressOf
RaiseDisplayClear
End Sub
''' <summary>
''' Raises the
DisplayClearedEvent visible to VSTA
''' </summary>
''' <remarks>Notice the
event delegate passed to the EventHelper is EventNameEvent not EventName.
''' This is due
to VB syntax.</remarks>
Private Sub RaiseDisplayClear()
EventHelper.Invoke(DisplayClearedEventEvent, Me,
EventArgs.Empty)
End Sub
End Class
''' ADD-IN
Private Sub AppAddIn_Startup(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles Me.Startup
AddHandler
DisplayClearedEvent, AddressOf AddIn_DisplayClear
End Sub
'manually added
event handling
Private Sub AddIn_DisplayClear()
addTextToListBox("Add-in saw display clear")
End Sub
'event handling
added through the drop down menus
Private Sub AppAddIn_DisplayClearedEvent(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DisplayClearedEvent
addTextToListBox("Add-in saw display clear (twice)")
End Sub
V) Using EventArgs in VSTA
Like forms, EventArgs based on the System.Windows.Forms
class cannot be passed between the host application and add-ins because they
are not serializable. One work around
for this is to use custom event args.
The custom event args should have serializable public properties to hold
information from the event args based on System.Windows.Forms. Below is the ButtonClickEventArgs class is
used in place of System.Windows.Forms.MouseEventArgs to pass information about
button clicks on the form to the add-ins.
''' HOST
''' <summary>
''' Custom event
args to hold button click information
''' to expose to
VSTA.
''' </summary>
''' <remarks>This wrapper class is used to pass information instead of
''' passing the MouseEventArgs directly because
System.Windows.Forms is
''' not serializable therefore cannot be passed.</remarks>
Public Class ButtonClickEventArgs
Inherits
EventArgs
''' <summary>
''' Name of the
button which was clicked
''' </summary>
Public ReadOnly Property
ButtonName() As String
Get
Return
mButtonName
End Get
End Property
Private
mButtonName As String
''' <summary>
''' Which mouse
button was used- right or left.
''' </summary>
Public ReadOnly Property
MouseButton() As String
Get
Return
mMouseButton
End Get
End Property
Private
mMouseButton As String
''' <summary>
''' Creates a new
ButtonClickEventArgs storing which button was clicked
''' and which mouse button was used.
''' </summary>
Public Sub New(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
'determine
which button was clicked and with which mouse button
Dim
Button As System.Windows.Forms.Button = CType(sender, System.Windows.Forms.Button)
mButtonName = Button.Name
mMouseButton = e.Button.ToString()
End Sub
End Class
''' HOST
''' <summary>
''' An event
handler type for button clicks.
''' </summary>
Public Delegate Sub
ButtonClickEventHandler(ByVal sender As Object, ByVal e As
ButtonClickEventArgs)
''' HOST
''' <summary>
''' Main class
of the host application.
''' VSTA entry
point.
''' </summary>
Public Class MainApplication
''' <summary>
''' Prepares the
host application to run.
''' Sets up the
list of objects and the form.
''' Hooks up form
events to methods that will raise VSTA visible events.
''' </summary>
Public Sub New()
'instantiate
the form and lis tof messages
mMyForm = New
MainForm
mMyObjects = New
List(Of MainObject)
'hook up the
event handling to the form
HookUpEvents()
End Sub
''' <summary>
''' Event raised
when any button is selected
''' </summary>
''' <remarks>Exposed to
VSTA and not used by the host</remarks>
Public Event ButtonClickEvent As
ButtonClickEventHandler
''' <summary>
''' Associates
form events with methods that will raise
'''
VSTA visible events.
''' </summary>
Private Sub HookUpEvents()
'Event
handling for all buttons- any button click raises
'the ButtonClickEvent which is exposed to
VSTA and called
'in RecordClick
AddHandler
MyForm.cmdOpen.Click, AddressOf RecordClick
End Sub
''' <summary>
''' Records any
button clicks in the display.
''' </summary>
''' <remarks>Raises the
ButtonClickEvent which is
''' visible to
VSTA.</remarks>
Private Sub RecordClick(ByVal
sender As Object,
ByVal e As
EventArgs)
'raise the
event exposed to VSTA for any button click
EventHelper.Invoke(ButtonClickEventEvent, Me,
_
New
ButtonClickEventArgs(sender, CType(e, _
System.Windows.Forms.MouseEventArgs)))
End Sub
End Class
''' ADD-IN
Private Sub AppAddIn_Startup(ByVal
sender As Object,
ByVal e As
System.EventArgs) Handles Me.Startup
AddHandler
ButtonClickEvent, AddressOf AddIn_ButtonClick
End Sub
Private Sub AddIn_ButtonClick(ByVal
sender As Object,
ByVal e As
ButtonClickEventArgs)
'determine
which button was pressed
Dim
buttonName As String
= e.ButtonName
'determine
the mouse button that was used
Dim
mouseButton As String
= e.MouseButton
'display a
message that shows the add-in found the above info
addTextToListBox("VSTA add-in caught button click" &
vbNewLine & _
"Button:
" & buttonName & vbNewLine & _
"Mouse Button: " & mouseButton)
End Sub