This documentation is archived and is not being maintained.

Lesson 3: Data Input [Visio 2003 SDK Documentation]

Office 2003

The Microsoft Visual Basic® .NET project files that accompany this lesson can be found at \Samples\Tutorial\VBNet\Lesson3.

Table of contents



Using a Form to Get Shape Properties

Summary: Data Input


In this lesson we extend the COM add-in from Lesson 2: Event Handling to invoke a wizard that gathers user preferences for creating a simple flowchart. Through the wizard, the user can determine the number of flowchart shapes to draw and modify the shape properties. We extend the DocumentCreator class from the previous lesson so that the COM add-in creates a DocumentCreator object using the wizard data.

We demonstrate how to extend the COM add-in to get user input from a wizard implemented with Microsoft® Windows® Forms, and create a flowchart.

This lesson shows you how to:

  • Manage shape properties selected in the wizard through a custom ShapeProperties class and store them using the ArrayList class.
  • Implement the TutorialAddin wizard using Windows Forms.
  • Use the AlertResponse property to determine if the wizard and messages should be shown.
  • Display shape properties using the DataGrid class and allow the user to edit shape properties.
  • Add flowchart shapes to a page and and connect them.
  • Apply shape properties entered in the wizard to the shapes in the flowchart drawing.


To see the implementation of the sample application for this lesson, open the solution using Microsoft Visual Studio® .NET. The solution is found in the Lesson3 folder and is named Lesson3.sln.

Using a Form to Get Shape Properties

As shown in Lesson 2, the TutorialAddin sample responds to the user creating a new Visio document based on the Managed Tutorial.vst template. However, instead of simply drawing a single shape as we did in Lesson 2, we have extended the sample code to invoke the TutorialAddin wizard.

The wizard walks the user through the following sequence of steps:

  1. It asks the user whether to create a 4- or 8-shape (representing the steps) flowchart.
  2. It displays the default shape properties.

    By selecting cells in the displayed grid and editing the values, the user can modify these properties.

  3. It displays a summary page when the user has finished selecting the shape properties.

    When the user clicks the Finish button, the COM add-in draws the flowchart.

Checking Alert Response to Determine if the Wizard and COM Add-in Messages Boxes Should Appear

Visio includes a property, AlertResponse, that can be set to control whether Visio shows a modal user interface. The non-zero values returned from the AlterResponse property correspond to standard windows constants such as IDOK, IDCANCEL, etc. Solutions that display message boxes, dialog boxes, or wizards should check this property before displaying these items in the Visio user interface.

Before displaying the wizard, the COM add-in checks the AlertResponse property. If this property is 0, the wizard is shown. If the AlertResponse property returns IDOK (1) or IDYES (6), the drawing creation functionality continues to use the defaults from the wizard. If the property is set to any other value, no drawing creation occurs.

In this sample, most of the calls to the MsgBox function have been updated to check for the AlertResponse property before displaying the message. As part of that change, there is a new helper function in Shared.vb called DisplayException. This method is used to display errors in a message box if the AlertResponse is 0, or the Debug window if it is not equal to zero. This method is called in some of the sample code below.

Managing Shape Properties

We will need to manage two pieces of information about the flowchart that the COM add-in will draw: the number of shapes, and the properties for each shape.

We will store this information in private members of the Wizard class, as shown in the following declarations:

    Private shapeCountValue As Integer = 0
Private shapeListArray As New ArrayList()

The values in these private members represent the form state for the wizard. In order to maintain this state information, the DocumentCreator class instance is given a reference to a Wizard object when it is created. The Wizard object displays the wizard and holds the form state information. The Wizard class exposes two public properties, ShapeCount and ShapeList, that allow access to the wizard data.

The shape properties are stored using the ArrayList class. ArrayList is a smart array, which means it dynamically grows and shrinks as elements are added or removed from it. If we want to add a new element to the ArrayList, we call the Add method. The ArrayList makes it easy to bind the shape properties to the DataGrid control for display to the user. Note that there is no need to declare the type of the elements stored in our ArrayList member because ArrayList can contain heterogeneous objects.

For the shape properties that the wizard allows the user to modify, we create a ShapeProperties class. Each element of the shapeList member will be a ShapeProperties object. The ShapeProperties class contains five private members, representing the shape master, fill color, line color, shape text, and hyperlink, as shown in the following declarations:

    Private shapeTypeString As String
Private fillColorString As String
Private lineColorString As String
Private textString As String
Private hyperlinkString As String

The ShapeProperties class exposes public properties to get and set these values. It also has a constructor that allows you to initialize all the members. This allows us to initialize a default flowchart as follows:

    Dim shapeIndex As Integer

shapeCountValue = 4

' Initialize shape properties.
For shapeIndex = 1 To ShapeCount
    shapeListArray.Add(New ShapeProperties(PROCESS_MASTER, _
    COLOR_WHITE, COLOR_BLACK, "Add shape text", _
    "Add shape hyperlink"))

Using Windows Forms to Build the TutorialAddin Wizard

Now that we have a way to store the information for customizing the flowchart, we can build the TutorialAddin wizard. Each page of the wizard is a separate Form class, which is declared as follows:

    Imports System.Windows.Forms
Public Class Screen1
    Inherits Form

Inheriting from the Windows Forms base class gives us access to a wide array of form controls for customizing our wizard pages. The first wizard page contains two RadioButton controls, which allow the user to specify a 4- or 8-step flowchart.

To display this wizard page, we use the following code:

    Dim screen As Form
Dim result As DialogResult
result = screen.ShowDialog()

The ShowDialog method performs these tasks:

  • Makes the wizard modal with respect to Visio.
  • Allows the wizard to determine which button the user clicked (see the topic Navigating the wizard pages).
  • Displays the form (Figure 1).

In order to prevent the wizard form from appearing in the task pane, the form property ShowInTaskbar is set to False.

Managed Code Tutorial wizard page

Figure 1. First page of the TutorialAddin wizard allows the user to specify a 4- or 8-step flowchart

To affect the shapeCountValue member of the Wizard object, we need to pass a reference of the object to the form. This is done by adding a parameter to the Screen1 class's New operator as follows:

Public Sub New(ByVal wizard As Wizard)

To detect the user's selection, we listen for the Click event on the NextButton button. When the user makes a selection, we use the public properties on Wizard to modify its state.

The following code in the Click event handler examines the Checked property of the radio button and modifies the shape properties depending on whether the user has chosen 4 or 8 shapes:

    If Shapes4RadioButton.Checked Then

    If wizardObject.ShapeList.Count > 4 Then
        wizardObject.ShapeList.RemoveRange(4, 4)
    End If

    wizardObject.ShapeCount = 4


    Dim addShapes As Integer = 0

    If wizardObject.ShapeList.Count < 8 Then
        For addShapes = 1 To 4
            wizardObject.ShapeList.Add(New ShapeProperties( _
                "Add shape text", "Add shape hyperlink"))
    End If

    wizardObject.ShapeCount = 8

End If

Displaying Shape Properties

Now that we know the number of shapes, we can start modifying the shape properties. We can use the Windows Forms DataGrid control to display our five customizable shape properties to the user.

Choosing the ArrayList class to store our shape properties makes it easy to bind the shape properties data to the DataGrid control, as shown in the following code located in Screen2_LoadEventHandler:

    Dim tableStyle As New DataGridTableStyle()
Dim ShapeTypeColumn As New DataGridComboBoxColumn()
Dim ShapeTextColumn As New DataGridTextBoxColumn()
Dim FillColorColumn As New DataGridComboBoxColumn()
Dim LineColorColumn As New DataGridComboBoxColumn()
Dim HyperlinkColumn As New Windows.Forms.DataGridTextBoxColumn()

' Create a custom tableStyle for column display.
DataGrid1.DataSource = wizardObject.ShapeList()
tableStyle.MappingName = "ArrayList"

' Display shape type in a drop-down list
ShapeTypeColumn.MappingName = "ShapeType"
ShapeTypeColumn.HeaderText = "Type"
ShapeTypeColumn.ColumnComboBox.DropDownStyle = _
tableStyle.PreferredRowHeight = _
     (ShapeTypeColumn.ColumnComboBox.Height + 3)

' Display shape text in an edit box
ShapeTextColumn.MappingName = "Text"
ShapeTextColumn.HeaderText = "Text"
ShapeTextColumn.TextBox.MaxLength = 30

' Display fill color in a drop-down list
FillColorColumn.MappingName = "FillColor"
FillColorColumn.HeaderText = "Color"
FillColorColumn.ColumnComboBox.DropDownStyle = _

' Display line color in a drop-down list
LineColorColumn.MappingName = "LineColor"
LineColorColumn.HeaderText = "Line color"
LineColorColumn.ColumnComboBox.DropDownStyle = _

' Display hyperlink in an edit box
HyperlinkColumn.MappingName = "Hyperlink"
HyperlinkColumn.HeaderText = "Hyperlink"
HyperlinkColumn.TextBox.MaxLength = 255


Each GridColumnStyles item that we add to the DataGrid control allows us to specify the header text and the order that the columns are displayed in.

Note how the MappingName property corresponds to each public property that we expose in the ShapeProperties class. The following figure shows the second page in the wizard.

Manged Code Tutorial wizard shape properties page

Figure 2. Displaying shape properties

Navigating the Wizard Pages

On the second wizard page, we need to detect more than the standard Cancel or OK return value, so we implement a WizardResult property for the form. The IWizardResult interface defines this property, which is implemented by each wizard form.

The WizardResult property returns the following additional return values, defined in the WizardResults enumeration:

    Public Enum WizardResults
    buttonNone = 100
    buttonNext1 = 101
    buttonBack2 = 102
    buttonNext2 = 103
    buttonBack3 = 104
    buttonFinish = 105
End Enum


In the form, we set the private member wizardResultValue, whose value is returned by the WizardResult property, in the buttons Click event handler:

    Private Sub BackButton_ClickEventHandler( _
    ByVal sender As System.Object, _
    ByVal eventData As System.EventArgs) _
    Handles BackButton.Click

    wizardResultValue = WizardResults.buttonBack2

End Sub


Because each wizard form implements the IWizardResult interface, we can define a screen variable of the generic Form type and use polymorphism. We set screen to the derived form type depending on which wizard screen is currently shown. Then we cast screen to the IWizardResult interface type and check the return value. The Wizard class's GetShapeData method drives the wizard navigation process as follows:

    Dim screen As Form
Dim result As DialogResult
Dim wizardResult As WizardResults
Dim wizardScreen1 As New Screen1(Me)
Dim wizardScreen2 As New Screen2(Me)
Dim wizardScreen3 As New Screen3(Me)


    ' Show wizard.
    screen = wizardScreen1

        result = screen.ShowDialog()
        If result = System.Windows.Forms.DialogResult.Cancel Then
            Return False
            wizardResult = CType(screen, IWizardResult).WizardResult
        End If
            Select Case wizardResult
                Case Is = WizardResults.buttonNext1
                    screen = wizardScreen2
                Case Is = WizardResults.buttonBack2
                    screen = wizardScreen1
                Case Is = WizardResults.buttonNext2
                    screen = wizardScreen3
                Case Is = WizardResults.buttonBack3
                    screen = wizardScreen2
            End Select
    Loop Until wizardResult = WizardResults.buttonFinish

    Return True

Catch err As COMException
    DisplayException( _
           alertResponse, _
           "Exception in GetShapeData: " & _
End Try


Editing Shape Properties

The DataGrid control allows the user to select a shape. When the user clicks a cell in the grid, the cells control is enabled for editing. For example, a drop-down list is displayed (Figure 3) that allows the user to edit the properties for the selected shape. This is implemented by overriding the DataGridTextBoxColumn controls Edit method as follows:

    Protected Overloads Overrides Sub Edit(ByVal source As CurrencyManager, _
    ByVal rowNumber As Integer, ByVal boundsRect As Rectangle, _
    ByVal readOnly1 As Boolean, ByVal instantText As String, _
    ByVal cellIsVisible As Boolean)

    MyBase.Edit(source, rowNumber, boundsRect, readOnly1, _
        instantText, cellIsVisible)
    gridRowNumber = rowNumber
    sourceCurrencyManager = source
    ColumnComboBox.Parent = Me.TextBox.Parent
    ColumnComboBox.Location = Me.TextBox.Location
    ColumnComboBox.Size = New Size(Me.TextBox.Size.Width, _
    ColumnComboBox.Text = Me.TextBox.Text
    Me.TextBox.Visible = False
    ColumnComboBox.Visible = True

End Sub

This code replaces the text box for the shape color, line color, and shape type cell with a drop-down list box implemented in DataGridComboBoxColumn.vb. The text box control is hidden and the list box is made visible, displaying the list of possible shape types. When the user selects a shape type from the list, the flowchart shape properties are modified by overriding the DataGridTextBoxColumn control's Commit method:

    Protected Overloads Overrides Function Commit( _
    ByVal dataSource As CurrencyManager, _
    ByVal rowNumber As Integer) As Boolean
    If isEditing Then
        isEditing = False
        SetColumnValueAtRow(dataSource, rowNumber, _
    End If

Shape properties wizard page with pull-down menu

Figure 3. Editing shape properties

Now that the shape properties are set, we can display a wizard summary page as shown in Figure 4.

Manged Code Tutorial wizard summary page

Figure 4. Wizard summary page

Drawing the Flowchart Shapes

Once the user is finished using the TutorialAddin wizard, the add-in is ready to draw the flowchart. To add the shapes, the CreateDrawing method iterates over the shapeList array, reading the master and dropping a shape of that type on the page in a random location as follows:

    pinX = CInt(random.NextDouble() * 10)
pinY = CInt(random.NextDouble() * 10)
shapeProp = CType(shapeList(stepID - 1), ShapeProperties)
shape = DropMasterOnPage(currentPage, _
    shapeProp.ShapeType, _


Note how we have to perform an explicit cast to the ShapeProperties type. This is because the ArrayList class stores its elements as generic objects.

The CreateDrawing method passes the following parameters to the DropMasterOnPage method: the name of the flowchart stencil, the master as specified by the user, and coordinates for dropping the shape. We use random coordinates because we will lay out and center the flowchart after all shapes are drawn and connected.

Now we can apply the remaining shape properties. Reading from the ShapeProperties element for each shape, we can set each property for the current shape. For example, the following code sets the shape text:

currentshape.Characters.Text = shapeProp.Text

Connecting the Flowchart Shapes

Once each shape is created, we connect the shapes that represent the flowchart steps. The CreateDrawing method calls the ConnectWithDynamicGlueAndConnector procedure:

    ' Connect previous step to the one just created.
If stepID > 1 Then
    ' Connect the two shapes.
    ConnectWithDynamicGlueAndConnector( _
        prevShape, shape)
End If

' Keep reference to previous shape for connecting steps.
prevShape = shape


The ConnectWithDynamicGlueAndConnector procedure accesses the flowchart stencil and its Dynamic Connector master. By holding a reference to the previous shape, the CreateDrawing method connects each new shape that it drops on the page to the previous shape.

Summary: Data Input

Lesson3 provides a quick way of designing a flowchart. Data is gathered using the Wizard class and its associated forms and displayed on the drawing page using the DocumentCreator class.

The TutorialAddin sample developed in this lesson has a high degree of functionality and can be customized easily for your applications. We will make one last change to the sample, but not a functional one.

In Lesson 4: Performance, we will improve the performance of the drawing code.