What's New for Developers in Visio 2007 (Part 1 of 2)

Saul Candib, Microsoft Corporation

Philippe-Joseph Arida, Microsoft Corporation

August 2006

Applies to: 2007 Microsoft Office Suites, Microsoft Office Visio 2007

Summary: This article introduces new features of interest to developers in Microsoft Office Visio 2007 and explains how to use them. What's New for Developers in Visio 2007 (Part 2 of 2) describes all the new objects and members of the Visio VBA object model, and newly deprecated existing members. It also lists and describes new ShapeSheet cells and functions. (23 printed pages)

Contents

  • Introduction to New Developer Features in Visio 2007

  • Connecting to Data Sources

  • Linking Data to Shapes in a Visio Drawing

  • Displaying Linked Data Graphically

  • Refreshing Linked Data and Resolving Conflicts

  • Other Additions to the Visio Object Model

  • Conclusion

  • Additional Resources

Introduction to New Developer Features in Visio 2007

New developer-related features include data connectivity and data display, connecting shapes automatically, monitoring and filtering mouse-drag actions, and applying theme colors and theme effects. Each of these features has an associated application programming interface (API) that makes it possible to control the feature programmatically. This article provides several Microsoft Visual Basic for Applications (VBA) code samples showing how to use the new APIs.

You can control several new features in Microsoft Office Visio 2007 programmatically, including connecting to a data source, linking shapes to data, displaying linked data graphically, connecting shapes to one another automatically (AutoConnect), monitoring and filtering mouse-drag actions, and applying theme colors and theme effects.

The most important new programmable features relate to data connectivity. There are four aspects of data connectivity in Visio:

  • Connecting to a data source

  • Linking shapes to data

  • Displaying linked data graphically

  • Refreshing linked data that has changed in the data source, updating linked shapes, and resolving any conflicts

Each of these aspects has new objects and members associated with it in the Visio object model.

Connecting to Data Sources

To connect your Visio drawing to a data source programmatically, you can use the new additions to the Visio API for data connectivity, which include the following objects and their associated members:

  • DataRecordsets collection

  • DataRecordset object

  • DataConnection object

  • DataRecordsetChangedEvent object

  • DataColumns collection

  • DataColumn object

For a brief description of each object, see New Automation Objects and Members in What's New for Developers in Visio 2007 (Part 2 of 2). To see a diagram of all the members of each object, click the object names in the list.

About Data Recordsets and Data Connections

Each Visio Document object has a DataRecordsets collection, which is empty until you make a connection to a data source. To connect a Visio document to a data source, you add a DataRecordset object to the DataRecordsets collection of the document. A DataRecordset object has a DataColumns collection of DataColumn objects, each of which is mapped to a corresponding column (field) in the data source.

Data sources you can connect to include Microsoft Office Excel worksheets, Microsoft Office Access databases, Microsoft SQL Server databases, Microsoft SharePoint lists, and other OLEDB or ODBC data sources, such as an Oracle database. When you add a DataRecordset object by connecting to one of these data sources, Visio abstracts the connection in a DataConnection object, and the DataRecordset object is said to be connected.

You can also add a DataRecordset object by using an XML file that conforms to the ActiveX Data Objects (ADO) XML schema as the data source. The resulting DataRecordset object is said to be connection-less.

The connection between a data source and a DataRecordset object goes only one way—from the data source to the Visio drawing. If data in the source changes, you can refresh the data in the drawing to reflect those changes. You cannot, however, make changes in the data in the drawing and then push those changes back to the data source.

Adding DataRecordset Objects

To add a DataRecordset object to the DataRecordsets collection, you can use one of the following three methods, depending on the data source you want to connect to and whether you want to pass the method a connection string and query command string or a saved Microsoft Office Data Connection (ODC) file that contains the connection and query information:

  • DataRecordsets.Add

  • DataRecordsets.AddFromConnectionFile

  • DataRecordsets.AddFromXML

The following VBA sample macro shows how you might use the Add method to connect a Visio drawing to data in a Microsoft Office Excel 2007 worksheet, in this case, in the ORGDATA.XLS sample workbook that is included with Visio 2007.

Public Sub AddDataRecordset()
    Dim strConnection As String
    Dim strCommand As String
    Dim strOfficePath As String
    Dim vsoDataRecordset As Visio.DataRecordset
    strOfficePath = Visio.Application.Path
    strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
                       & "User ID=Admin;" _
                       & "Data Source=" + strOfficePath _
                       & "SAMPLES\1033\ORGDATA.XLS;" _
                       & "Mode=Read;" _
                       & "Extended Properties= _
                       & ""HDR=YES;IMEX=1;MaxScanRows=0; _
                       & Excel 12.0;"";" _
                       & "Jet OLEDB:Engine Type=35;"
    strCommand = "SELECT * FROM [Sheet1$]"
    Set vsoDataRecordset = ActiveDocument.DataRecordsets.Add(_
                  strConnection, strCommand, 0, "Org Data")
End Sub

The Add method returns a DataRecordset object and takes four parameters:

  • ConnectionIDOrString   The ID of an existing DataConnection object or the connection string to specify a new data-source connection. If you pass the ID of an existing DataConnection object that is currently being used by one or more other data recordsets, the data recordsets become a transacted group recordset. All data recordsets in the group are refreshed whenever a data-refresh operation occurs.

    You can determine an appropriate connection string by first using the Data Selector Wizard in the Visio user interface (UI) to make the same connection, recording a macro while running the wizard, and then copying the connection string from the macro code.

  • CommandString   The string that specifies the database table or Excel worksheet and specifies the fields (columns) within the table or worksheet that contain the data you want to query. The command string is also passed to the DataRecordset.Refresh method when the data is refreshed in the recordset.

  • AddOptions   A combination of one or more values from the VisDataRecordsetAddOptions enumeration. These values specify certain data recordset behaviors, and make it possible, for example, to prevent the queried data in the recordset from appearing in the External Data window in the Visio UI or from being refreshed by user actions. After you assign this value, you cannot change it for the life of the DataRecordset object.

  • Name   An optional string that gives the data recordset a display name. If you specify that data from the recordset is to be displayed in the External Data window in the Visio UI, the name you pass appears on the tab of the window that corresponds to the data recordset.

In the example, there is no existing data connection, so for the first parameter of the Add method, you pass strConnection, the connection string you defined. For the second parameter, you pass strCommand, the command string you defined, which directs Visio to select all columns from the worksheet specified. For the third parameter of the Add method, you pass zero to specify default behavior of the data recordset, and for the last parameter, you pass Org Data, the display name defined for the data recordset.

The following sample code shows how to get the DataConnection object that was created when you added a DataRecordset object to the DataRecordsets collection. It prints the connection string associated with the DataConnection object in the immediate window by accessing the ConnectionString property of the DataConnection object.

Public Sub GetDataConnectionObject(vsoDataRecordset As Visio.DataRecordset)
    Dim vsoDataConnection As DataConnection
    Set vsoDataConnection = vsoDataRecordset.DataConnection
    Debug.Print vsoDataConnection.ConnectionString
End Sub

Similar to how you can get the connection string associated with a DataConnection object by accessing its ConnectionString property, you can get the command string associated with a DataRecordset object by accessing its CommandString property. Both of these properties are assignable, so you can change the data source associated with a DataRecordset object or the query associated with a DataConnection object at any time, although changes are not reflected in your drawing until you refresh the data. For more information about refreshing data, see Refreshing Linked Data and Resolving Conflicts.

Accessing Data in Data Recordsets Programmatically

When you import data, Visio assigns integer row IDs, starting with the number 1, to each data row in the resulting data recordset, based on the order of the rows in the original data source. Visio uses data row IDs to track the rows when they are linked to shapes and when data is refreshed. If you want to access data rows programmatically, you must use these data row IDs. For information about how data-refresh operations affect row order, see Refreshing Linked Data and Resolving Conflicts.

You can use the DataRecordset.GetDataRowIDs method to get an array of the IDs of all the rows in a data recordset, where each row represents a single data record. The GetDataRowIDs method takes as its parameter a criteria string, which is a string that conforms to the guidelines specified in the ADO API for setting the ADO.Filter property. By specifying appropriate criteria and using AND and OR operators to separate clauses, you can filter the information in the data recordset to return only certain data recordset rows. To apply no filter (that is, to get all the rows), pass an empty string (""). For more information about criteria strings, see Filter Property in the ADO 2.8 API Reference.

After you retrieve the data-row IDs, you can use the DataRecordset.GetRowData method to get all the data stored in each column in the data row. For more information about data columns, see the section, Getting and Setting Data-Column Properties.

The following sample code shows how to use the GetDataRowIDs and GetRowData methods to return the row ID of each row and then get the data stored in each column in every row of the data recordset passed in. It uses two nested For…Next loops to iterate through all the rows in the recordset and then, for each row, iterate through all the columns in that row. The code displays the information returned in the immediate window. Note that you pass an empty string to the GetDataRowIDs method to bypass filtering and get all the rows in the recordset. After you call the procedure, note that the first set of data shown (corresponding to the first data row) contains the headings for all the data columns in the data recordset.

Public Sub GetDataRecords(vsoDataRecordset As Visio.DataRecordset)
    Dim lngRowIDs() As Long
    Dim lngRow As Long
    Dim lngColumn As Long
    Dim varRowData As Variant
    'Get the row IDs of all the rows in the recordset.
    lngRowIDs = vsoDataRecordset.GetDataRowIDs("")
    'Iterate through all the records in the recordset.
    For lngRow = LBound(lngRowIDs) To UBound(lngRowIDs)
        varRowData = vsoDataRecordset.GetRowData(lngRow)
        'Print a separator between rows
        Debug.Print "------------------------------"
       'Print the data stored in each column of a particular data row.
        For lngColumn = LBound(varRowData) To UBound(varRowData)
            Debug.Print "Column #"; Trim(Str(lngColumn)) & " = " & _
                 VarRowData(lngColumn)
        Next lngColumn
    Next lngRow
End Sub

Linking Data to Shapes in a Visio Drawing

After you connect your Visio drawing to an external data source, you can link the shapes in the drawing to data from that source programmatically. You can link one or more shapes to a single row of data in a data recordset or to multiple rows of data in different data recordsets. However, you cannot link shapes to multiple rows of data in the same recordset.

You can link existing shapes to data, one shape at a time or as a group; or, you can create shapes and link them to data simultaneously. You can specify the correspondence between shapes and data rows, if you know it, or you can let Visio determine the correspondence automatically, based on a comparison between existing shape data and data in the data recordset.

After you link shapes to data, you can display that data graphically by adding data graphics to shapes. For more information about data graphics, see Displaying Linked Data Graphically.

The DataRecordset and DataColumn objects and the DataColumns collection expose several properties, methods, and events that facilitate data linking. In addition, several new members of existing objects in the Visio object model, including the Application, Document, Page, Selection, Shape, and Window objects, are related to data-linking.

Data-Linking and Shape Data

Linking shapes to data relies on the fact that you can assign shape data to all Visio shapes. In previous versions of Visio, shape data was called custom properties.

To access and assign shape data in the Visio UI, on the Data menu, click Shape Data. Alternatively, you can access and assign shape data manually or programmatically in the Visio ShapeSheet spreadsheet. To display the ShapeSheet spreadsheet (ShapeSheet) for a selected shape, right-click the shape and click Show ShapeSheet. To see this command, you must be running Visio in developer mode. To run Visio in developer mode, on the Tools menu, click Options, click Advanced, select Run in developer mode, and then click OK.

Within the ShapeSheet, shape data is contained in the Shape Data section (previously called the Custom Properties section). To maintain backward-compatibility, existing object members retain "custom property" or "custom properties" in their name.

If you do not assign shape data for a given shape, no Shape Data section appears in the ShapeSheet. You can add a Shape Data section to a ShapeSheet by displaying the ShapeSheet as described previously: right-click anywhere in the ShapeSheet window and click Insert Section, select Shape Data, and then click OK.

After you link shapes to data, many of the columns of the Shape Data section correspond closely to the properties of the DataColumn object. For example, the Label column in the Shape Data section, which provides the label that appears for a particular shape data item in the Shape Data dialog box, corresponds to the DataColumn.DisplayName property, which controls the name that appears for the associated data column in the External Data window.

For more information about the DataColumn object, see the section, Getting and Setting Data-Column Properties. For more information about creating shape data programmatically in the Visio ShapeSheet, see the Microsoft Office Visio 2003 SDK.

Identifying Shapes, Data Recordsets, and Data Rows

Visio uses unique ID numbers to identify shapes, recordsets, and data rows. Shape IDs are unique only within the scope of the page they are on. After you determine these numbers, you can pass them to methods of the Visio data-related objects to specify exactly how the shapes in your diagram should link to data rows in the available data recordsets.

To determine the ID for a shape, get the Shape.ID property value. In addition, Visio also gives shapes unique IDs or GUIDs. The Page.ShapeIDsToUniqueIDs method takes an array of shape IDs, in addition to an enumeration value from VisUniqueIDArgs specifying whether to get, get or make, or delete shape GUIDs. The Page.ShapeIDsToUniqueIDs method also returns an array of unique IDs for the shapes passed in. Conversely, if you know the unique IDs of a set of shapes, you can use the Page.UniqueIDsToShapeIDs method to obtain the shape IDs for those shapes. For a selection of shapes, use the Selection.GetIDs method to get the shape IDs of the shapes.

To determine the ID for a DataRecordset object you add to the DataRecordsets collection, get the DataRecordset.ID property value. To determine the IDs for each of the rows in a data recordset, call the DataRecordset.GetDataRowIDs method, which returns an array of row IDs. For more information, see the section, Accessing Data in Data Recordsets Programmatically.

Creating Shapes Linked to Data

When you want to create shapes that are already linked to data, on a drawing page that either does not contain any shapes or contains shapes other than the ones you want to link, you can use the Page.DropLinked method and the Page.DropManyLinkedU method to create one or more additional shapes already linked to data. These methods resemble the existing Page.Drop and Page.DropManyU methods in that they create additional shapes at a specified location on the page; but they also create links between the new shapes and specified data rows in a specified data recordset.

The DropLinked method returns the new, linked Shape object and takes the following parameters:

  • ObjectToDrop   The particular shape (a Rectangle shape, for example) that you want to create.

  • x   The x-coordinate of the center of the new shape on the page.

  • y   The y-coordinate of the center of the new shape on the page.

  • DataRecordsetID   The value of the ID property of the DataRecordsetobject that contains the data row to link to.

  • DataRowID   The value of the ID property of the data row to link to.

  • ApplyDataGraphicAfterLink   A Boolean value specifying whether to apply the shape's data graphic automatically if it already has one, or if not, whether to apply the most recently used data graphic. The default is not to apply a data graphic. For more information about data graphics, see the section, Displaying Linked Data Graphically.

The following sample code shows how to use the DropLinked method to create a shape on the active drawing page, centered at page coordinates (2, 2), and linked to a data row. It takes the DataRecordset object passed in, gets its ID, and then passes that ID (along with the ID of the data row to link to) to the DropLinked method. The dropped shape is a simple rectangle from the Basic_U.VSS stencil, which the code opens, docked in the Visio drawing window.

In this example, the ID of the data row is set to 1; before running the code, ensure that a row with that ID exists, or change the ID value in the code.

Public Sub DropLinkedShape(vsoDataRecordset As Visio.DataRecordset)
    Dim vsoShape As Visio.Shape
    Dim vsoMaster As Visio.Master
    Dim dblX As Double
    Dim dblY As Double 
    Dim lngRowID As Long
    Dim lngDataRecordsetID As Long
    lngDataRecordsetID = vsoDataRecordset.ID
    Set vsoMaster = _
        Visio.Documents.OpenEx("Basic_U.VSS", 0).Masters("Rectangle")
    dblx = 2
    dbly = 2
    lngRowID = 1
    Set vsoShape = ActivePage.DropLinked(vsoMaster, dblX, dblY, _
              lngDataRecordsetID, lngRowID, True)
End Sub

The DropManyLinkedU method similarly creates a set of linked shapes, returned as an array of shape IDs. It takes as parameters arrays of shapes to drop, coordinates, and data rows to link to. Entries at corresponding array-index positions determine how shapes and data rows are related and where on the page individual shapes are dropped.

Linking Existing Shapes to Data

When you know exactly how one or more existing shapes in a Visio drawing and one or more rows in a data recordset correspond to one another, you can link the existing shapes to data in the following ways:

  • Link a single shape to a single data row

  • Link a selection of shapes to one or more data rows

  • Link multiple shapes to multiple data rows

In addition, if you do not know the exact shape for data mapping, you can direct Visio to make the best match possible, based on limited matching information that you provide.

Linking a Single Shape to a Data Row

To link a single shape to a single data row, use the Shape.LinkToData method. This method takes a data recordset ID and data row ID and an optional Boolean flag specifying whether to display the linked data in a data graphic. The default is to display the data graphic.

Linking Multiple Shapes to Data

Two members of the Selection object, the LinkToData method and the AutomaticLink method, in addition to the Page.LinkShapesToDataRows method, make it possible to link one or more existing shapes in a selection to data.

The Selection.LinkToData method functions much like the same method of the Shape object, except that it links a selection of shapes (instead of a single shape) to a single data row.

If you are unsure about the correspondence between shapes and data rows, but you know a match exists between a specific attribute of every shape and the data in one column in the data recordset, the Selection.AutomaticLinkmethod provides a way to link a selection of existing shapes to multiple rows of data. Note that it must be the same attribute for all shapes. For more information about this method, see the section, Linking to Data Automatically.

The Page.LinkShapesToDataRows method is similar to the Selection.LinkToData method because it links multiple shapes. However, you use this method to link shapes on the same page, rather than shapes in a selection, to data. The LinkShapesToDataRows method links shapes to multiple data rows. The LinkToData method links multiple shapes to a single row. To link shapes, pass the LinkShapesToDataRows method a pair of arrays: one for shapes, and one for data rows. Note that the matching array positions must correspond. As a result, for example, the shape at position 1 in the shape array is linked to the data at position 1 in the data row array. Again, when you call the method, you can optionally specify whether to apply an existing data graphic to linked shapes.

Linking to Data Automatically

You can use the Selection.AutomaticLink method to link shape data values in selected shapes—that is, shapes assigned to a Selection object—to data rows in a data recordset automatically—that is, without specifying the exact correspondence of all shapes and data rows. To provide Visio with enough information to create the links, however, you must supply at least one set of matching data: the name of a column in the database, a shape attribute type, and, if necessary, a shape value, all at the same index position of the corresponding arrays you pass to the method.

The shape attribute type indicates the attribute of the shape to base the matching upon. The attribute can be the value of a shape data item (formerly known as a custom property value), shape text, or another of the values specified in the VisAutoLinkFieldTypes enumeration.

For example, suppose that your drawing contains a selection of shapes representing different employees. Their shape text identifies the shapes, which in this case would be the respective employee's names. (You could use some of the employee names from the OrgData.xls workbook that is included with Visio 2007, and then connect to that data source.) To connect these shapes to a database where each employee's data constitutes a row in the database, you pass the following parameters to the AutomaticLink method:

  • DataRecordsetID   The value of the IDproperty of the DataRecordset object that contains the data rows to link to. In the example that follows, you pass an existing data recordset to the procedure and get its ID.

  • ColumnNames()   A string array consisting of names of columns in the database. At least one position in the array must have a value that corresponds to the values in the same position in the AutoLinkFieldTypes and FieldNames arrays. In the following example, you pass an array that contains the Name column name at array position 0.

  • AutoLinkFieldTypes()   An array of Long values from the VisAutoLinkFieldTypes enumeration, consisting of shape attribute types. At least one position in the array must have a value that corresponds to the values in the same position in the ColumnNames and FieldNames arrays. In the following example, you pass the enumeration value visAutoLinkShapeText at array position 0.

  • FieldNames()   A string array consisting of shape values. At least one position in the FieldNames array must have a value that corresponds to the values in the same position in the ColumnNamesand AutoLinkFieldTypes arrays.

    For most values of AutoLinkFieldTypes, for example, visAutoLinkShapeText, it is not necessary to specify the FieldNames value; you can pass the null value instead. That is the case in the following example, so you pass an empty string.

    However, when you pass the visAutoLinkCustPropsLabel, visAutoLinkUserRowName, visAutoLinkPropRowNameU, or visAutoLinkUserRowNameU values of AutoLinkFieldTypes, you must pass a value for FieldNames to fully specify the shape data item to compare to the data column name.

  • AutoLinkBehavior   A value from the VisAutoLinkBehaviors enumeration. These enumerated values provide options to customize the method, for example, to replace existing links with new ones. The following example passes the default value, 0.

  • ShapeIDs()   An array that the method fills with the IDs of linked shapes when it returns.

The following sample shows one way to use the AutomaticLink method to link shapes and data automatically.

Public Sub LinkToDataAutomatically(vsoDataRecordset As Visio.DataRecordset)
    Dim vsoSelection As Visio.Selection
    Dim columnNames(1) As String
    Dim fieldTypes(1) As Long
    Dim fieldNames(1) As String
    Dim shapesLinked() As Long
    columnNames(0) = "Name"
    fieldTypes(0) = Visio.VisAutoLinkFieldTypes.visAutoLinkShapeText
    fieldNames(0) = ""
    ActiveWindow.DeselectAll
    ActiveWindow.SelectAll
    Set vsoSelection = ActiveWindow.Selection
    vsoSelection.AutomaticLink vsoDataRecordset.ID, _
                    columnNames, _
                    fieldTypes, _
                    fieldNames, 0, shapesLinked
End Sub

Use the following methods, described in Table 2 in this document, to determine which shapes are linked to data. Knowing how shapes are linked to data can help prevent conflicts and broken links:

  • Page.GetShapesLinkedToData

  • Page.GetShapesLinkedToDataRow

  • Shape.GetLinkedDataRow

  • Shape.GetCustomPropertyLinkedColumn

  • Shape.GetCustomPropertiesLinkedToData

  • Shape.IsCustomPropertyLinked

As their names imply, you can use the Shape.BreakLinkToData method and the Selection.BreakLinkToData method to break existing links between shapes and data programmatically. In addition, various changes made in the UI can break these links. For example, when users delete a data recordset, linked row, or linked shape, or when users click Unlink from Row on a shape's shortcut menu or Unlink on a row's shortcut menu, they can cause broken links.

Except when a user deletes a data recordset, row, or shape from the UI, all of these actions fire the Shape.ShapeLinkDeleted event. You can also use the methods listed in the previous section to determine link status.

Getting and Setting Data-Column Properties

Every DataRecordset object contains a DataColumnscollection of all the DataColumn objects associated with the DataRecordset. These objects enable you to map data columns to cells in the Shape Data section of the ShapeSheet.

The following sample shows how to get the value of the Label cell in the Shape Data section for the first column in the data recordset passed to the method and display it in the immediate window. Then it sets the value and displays the new value.

Changing this value changes the label of the shape data item in the Shape Data dialog box for all shapes linked to rows in the data recordset. To get and set the Label cell value, you pass the visDataColumnPropertyDisplayName value from the VisDataColumnProperties enumeration to the DataColumn.GetProperty method and the DataColumn.SetProperty method.

Public Sub ChangeColumnProperties(vsoDataRecordset As Visio.DataRecordset)
    Dim strPropertyName As String
    Dim strNewName As String
    Dim vsoDataColumn As Visio.DataColumn

    strNewName = "New Property Name"
    Set vsoDataColumn = vsoDataRecordset.DataColumns(1)
    strPropertyName = _
        vsoDataColumn.GetProperty(visDataColumnPropertyDisplayName)
    Debug.Print strPropertyName
    vsoDataColumn.SetProperty visDataColumnPropertyDisplayName, _
        strNewName
    strPropertyName = _
        vsoDataColumn.GetProperty(visDataColumnPropertyDisplayName)
    Debug.Print strPropertyName
End Sub

Displaying Linked Data Graphically

After you link shapes in your Visio drawing to rows in a data recordset, you can graphically display the linked data programmatically. For example, suppose that your drawing contains several data-linked shapes, each of which represents a project at a particular stage of completion. You might associate a progress bar with a particular item of shape data, such as the percentage of project completion. You could then apply the progress bar to a selection of project shapes and show each project's progress toward completion visually.

Overview of Data Graphics and Graphic Items

To make it easier to display data graphically, Visio 2007 introduces the concept of data graphics and a new type of Master object called a data graphic master, which is represented in the VisMasterTypes enumeration by the value visTypeDataGraphic. To add a Master object of type visTypeDataGraphic to the Masters collection, you must use the new Masters.AddEx method.

Visio includes several types of masters, including shape masters. If you create an instance of a shape master, it becomes a shape. Visio also includes fill pattern masters, line pattern masters, and line-end masters, for which you cannot create instances. You apply these masters to shapes to impart the master pattern to the shape. Data graphic masters are more like pattern masters, because you do not create instances of them. Instead, you apply them to shapes as you do line pattern masters and fill pattern masters.

Data graphic masters correspond to the data graphics that appear in the Data Graphics task pane in the Visio UI. A data graphic master consists of one or more graphic items. Graphic items are Visio shapes designed to be ready-made visual components that you can associate with shape data to display that data graphically, based on rules that you define, and at a position that you specify, relative to the shape.

Visio provides graphic items of the following types:

  • **Text   **Displays data as text in a callout, at a specified position relative to the shape.

  • **Color by Value   **Changes the color of the shape based on a comparison between shape data and a particular value or range of values.

  • **Data Bar   **Uses bar charts and graphs to display data, at a specified position relative to the shape.

  • **Icon Set   **Displays one of a set of icons that represents a data value or condition, at a specified position relative to the shape.

Visio provides a variety of standard data graphics that are already populated with graphic items. If you want to apply a data graphic to your shapes that has a different combination of graphic items, you can create a custom data graphic.

You should use the Visio UI to create a data graphic and add graphic items to it.

To create data graphics in the UI

  1. On the Data menu, click Display Data on Shapes to open the Data Graphics task pane.

  2. Click New Data Graphic and then, in the New Data Graphic dialog box, click New Item.

  3. In the dialog box that opens, customize the item, and then use the same method to add custom items.

You can also create data graphic masters and populate them with existing graphic items programmatically. You cannot create graphic items programmatically, but you can customize the behavior of existing data graphics. You can also use code to change the behavior and position of graphic items, and to change the rules (called expressions) that define how individual graphic items display data.

After you create a data graphic that contains a custom combination of graphic items and define the behavior of those graphic items, you can apply the data graphic to data-linked shapes programmatically.

New Data Graphics Objects and Members

In addition to the new Master objects of type visTypeDataGraphic described in the previous section, Visio 2007 adds the following new objects and their associated members to the data graphics API:

  • GraphicItems collection

  • GraphicItem object

For a brief description of these objects, see New Automation Objects and Members in What's New for Developers in Visio 2007 (Part 2 of 2).

Visio 2007 also adds several new members of existing objects as part of the data graphics API. For example, the Shape.DataGraphic property and the Selection.DataGraphic property enable you to apply data graphics to shapes and selections respectively. The read-only Shape.IsDataGraphicCallout property indicates whether a specific shape is functioning as a data graphic item in your drawing.

Applying Data Graphics to Data-Linked Shapes

The following example shows how to use the Selection.DataGraphic property to apply an existing custom data graphic that you create in the UI to a selection of shapes in your drawing.

Public Sub ApplyDataGraphic()
    Dim vsoSelection As Visio.Selection
    ActiveWindow.SelectAll
    Set vsoSelection = ActiveWindow.Selection
    Set vsoSelection.DataGraphic = _
        ActiveDocument.Masters("MyCustomDataGraphic")
End Sub

Customizing the Behavior of Data Graphic Masters

You can use the Master.DataGraphicHidden property and the Master.DataGraphicHidesText property to customize certain aspects of the behavior of data graphic masters.

The DataGraphicHidden property determines whether a data graphic master appears in the Data Graphics task pane in the Visio UI. If you set the value of this property to True for a given master, the master does not appear in the list of data graphics in the gallery. The default value of the property is False.

The DataGraphicsHidesText property determines whether applying a data graphic master hides the text of the shape to which it is applied (the primary shape in the case of a group shape.) The default value of this property also is False.

The GraphicItem.UseDataGraphicPosition property determines whether to use the current default callout position for graphic items of the data graphic master to whose GraphicItems collection a graphic item belongs. The default callout position for graphic items in the GraphicItems collection of a Master object of type visTypeDataGraphic is specified by the settings of the Master.DataGraphicVerticalPosition property and the Master.DataGraphicHorizontalPosition property. If UseDataGraphicPosition is True, the graphic item is positioned according to the default setting. If UseDataGraphicPosition is False, its position is determined by the settings of the GraphicItem.VerticalPosition property and the GraphicItem.HorizontalPosition property.

Also, if the HorizontalPosition and VerticalPosition property values of a graphic item are equal to the DataGraphicHorizontalPosition and DataGraphicVerticalPosition property values, the value of the UseDataGraphicPosition property for that graphic item is automatically set to True.

Note, however, that you can manually reposition a data graphic that was applied to a shape by using the control handle of the data graphic. A position set in this way takes precedence over the position specified by property settings.

The Master.DataGraphicShowBorder property determines whether a border is displayed around graphic items that are in default positions relative to the shape to which a data graphic is applied. By default, the border is hidden.

Creating Data Graphics Programmatically

The following example shows how to create a data graphic master, add an existing graphic item to it, and then modify the graphic item. This example uses the Masters.AddEx method to add a new data graphic master to the Masters collection of the current document. Next, it uses the Master.Open method to get a copy of an existing data graphic master to edit. For more information about why it is necessary to edit a copy of a master, instead of the master itself, see Open Method [Visio 2003 SDK Documentation].

Next, this example uses the GraphicItems.AddCopy method to add a copy of an existing graphic item to the GraphicItems collection of the new master, and the GraphicItem.SetExpression method to modify the data field that the graphic item represents. It also sets the GraphicItem.PositionHorizontal property to modify the horizontal position of the graphic item relative to the shape to which it is applied.

Finally, it sets the Master.DataGraphicHidesText property to True to hide the text of the shape, and closes the copy of the master, which applies the changes to existing shapes to which this data graphic master is applied. You can then apply the new data graphic master to additional shapes.

Public Sub AddNewDataGraphicMaster()
    Dim vsoMaster As Visio.Master
    Dim vsoMasterCopy As Visio.Master
    Dim vsoMaster_Old As Visio.Master
    Dim vsoGraphicItem As GraphicItem
    Dim vsoGraphicItem_Old As Visio.GraphicItem
    Set vsoMaster = ActiveDocument.Masters.AddEx(visTypeDataGraphic)
    Set vsoMasterCopy = vsoMaster.Open
    Set vsoMaster_Old = ActiveDocument.Masters("old_master_name")
    Set vsoGraphicItem_Old = vsoMaster_Old.GraphicItems(1)
    Set vsoGraphicItem = _
         vsoMasterCopy.GraphicItems.AddCopy(vsoGraphicItem_Old)
    vsoGraphicItem.SetExpression visGraphicExpression, _
         "new_data_field_name"
    vsoGraphicItem.PositionHorizontal = visGraphicLeft
    vsoMasterCopy.DataGraphicHidesText = True;
    vsoMasterCopy.Close
End Sub

The preceding code assumes that you know the name of the existing data graphic master that contains one or more graphic items you want to add to the new master, and that you know the IDs of one or more graphic items you want to add to the master. You can determine the name of an existing data graphic master by moving your mouse over the master in the Data Graphics task pane. You can also determine master names and IDs by iterating through the Masters collection in the current document, as shown in this code example.

    For intCounter = 1 To ActiveDocument.Masters.Count
        If ActiveDocument.Masters(intCounter).Type = _
                 visTypeDataGraphic Then
        Debug.Print ActiveDocument.Masters(intCounter).Name, _
                 ActiveDocument.Masters(intCounter).ID
        End If
    Next

Similarly, you can iterate through the GraphicItems collection of a master to determine the values of the ID property and the Tag property of an existing graphic item, as shown in the following example. The Tag property is a string that Visio does not use. It is empty by default. However, you can set its value to make it easier to identify individual graphic items programmatically.

    For intCounter = 1 To (vsoMaster_Old.GraphicItems.Count)
        Debug.Print vsoMaster_Old.GraphicItems(intCounter).ID, _
                 oldMaster.GraphicItems(intCounter).Tag
    Next

To see a code sample that shows how to customize data graphics programmatically, download the Visio 2007: Software Development Kit and see the Code Samples Library.

Refreshing Linked Data and Resolving Conflicts

When data changes in the data source to which your drawing is connected, you can refresh the data in your Visio drawing to reflect those changes. You can specify that Visio refresh data automatically at a specified interval by setting the DataRecordset.RefreshInterval property. You can refresh data programmatically by calling the DataRecordset.Refresh method.

You can also resolve any conflicts in the relationship between shapes and rows of data. Conflicts can occur if you refresh the data recordset and some data rows to which shapes were linked before the refresh operation no longer exist, because of changes to the data source. Other conflicts are possible when two or more rows in the refreshed recordset have identical primary keys.

Refreshing Linked Data Automatically

When you create a DataRecordset object, its RefreshInterval property is set to the default, 0. This setting indicates that data is not refreshed automatically. By setting DataRecordset.RefreshInterval to a positive Long value, you can specify the time in minutes between automatic refreshes. The minimum interval you can specify is one minute. This setting corresponds to the value a user can set in the Configure Refresh dialog box.

To determine the date and time of the last refresh operation, get the DataRecordset.TimeRefreshedproperty.

Additionally, the DataRecordset.RefreshSettings property enables you to customize automatic refreshes of data. By setting this property to a combination of the values in the VisRefreshSettings enumeration, you can specify that either or both of the following occur:

  • The UI for reconciling refresh conflicts (the Refresh Conflicts task pane) is disabled. (See the next section for more information.)

  • Refresh operations automatically overwrite changes to data made in the UI.

The default value for this property is 0, meaning that neither of these events occur.

Identifying Data Recordset Rows for Refresh Operations

Because shapes are linked by their shape IDs to specific data rows, when Visio refreshes linked data, it must determine which rows in the linked data recordset or recordsets were added, changed, or removed since the last time the data was refreshed.

To identify these rows, Visio uses the row IDs assigned to the rows in the data recordset. Visio can assign these row IDs two ways, depending on whether you designated primary keys for the data recordset when you created it.

Refreshing Data Recordsets That Do Not Have Primary Keys

When you create a data recordset, Visio assigns row IDs to all the rows in the recordset based on the existing order of the rows in the data source. Accordingly, the first row in the recordset is always assigned row ID 1, the second is assigned row ID 2, and so on.

Subsequently, data rows can be added or removed from the original data source. Then, when data is refreshed, the data recordset reflects those changes. As a result, row order in the data recordset may change.

For example, in a five-row data recordset, if the fourth row in the data source is removed, when Visio refreshes the data recordset connected to that data source, the fifth row in the data recordset becomes the new fourth row and is assigned row ID 4. Row ID 5 is removed from the data recordset. As a result, shapes linked to row ID 5 lose their links, and shapes linked to row ID 4 now get data from the row previously in the fifth position.

As you can see, not assigning primary keys to data recordsets when you create them can result in broken links between shapes and data, or in Visio linking shapes to rows other than the ones to which you want them linked.

Refreshing Data Recordsets That Have Primary Keys

You can help prevent these broken or mismatched links by assigning primary keys to data recordsets. A primary key identifies the name of the data column or columns that contain unique identifiers for each row. The value in the primary key column for each row uniquely identifies that row in the data recordset. Primary keys are often ID values, but you can set any column or combination of columns to be the primary key. However, to get consistent results when you refresh data, it is essential that you make the primary key column value (or set of values for multiple primary key columns) unique for each row.

As a result, when you refresh or when Visio refreshes a data recordset that includes primary keys, its rows retain the same row IDs they had before the refresh operation. Because Visio links shapes to data rows by ID—shape ID to row ID—and because row IDs remain the same after a refresh operation, data-linked shapes remain linked to the correct row. Note that row IDs are never recycled for a given a data recordset.

You can use the DataRecordset.GetPrimaryKey method to determine the existing primary key for a data recordset, if one is specified. This method returns the primary key setting for the data recordset, as a value from the VisPrimaryKeySettings enumeration. You can use single primary keys or composite primary keys. A single key bases row identification on the values in a single column. A composite primary key uses two or more columns to identify a row uniquely.

If the primary key setting is visKeySingle or visKeyComposite, the method also returns an array of primary key column-name strings. If the primary key setting is visKeyRowOrder (the default) the method returns an empty array of primary keys.

Similarly, you can use the DataRecordset.SetPrimaryKey method to specify the primary key setting for the data recordset, and the name of the column or columns that you want to set as the primary key column or columns. Remember, when you set primary keys, ensure that the column or columns you choose to be primary key columns contain unique values (or value sets) for each row.

Refreshing Linked Data Programmatically

To refresh a connected data recordset programmatically, call the DataRecordset.Refresh method. Calling this method executes the query string associated with the data recordset and then updates the linked shapes with the data returned by the query.

Calling the Refresh method on a particular DataRecordset object results in refreshing all other DataRecordset objects associated with the same DataConnection object (that is, those objects that have the same value for their DataConnection property). DataRecordset objects sharing the same DataConnection property value are called transacted data recordsets.

If calling Refresh results in conflicts, Visio displays the Refresh Conflicts task pane in the UI, unless you set the RefreshSettings property to include the visRefreshNoReconciliationUI enumerated value.

Before you refresh linked data, if you want to change the query Visio uses to retrieve the data to query a different table in the same database, set the DataRecordset.CommandString property to a new value. To connect to an entirely new data source, set both the DataRecordset.CommandString property value and the DataConnection.ConnectionString property value.

The DataRecordset.GetLastDataError method gets the ADO error code, ADO description, and data recordset ID associated with the most recent error that resulted from adding a new data recordset or from refreshing the data in an existing data recordset.

Identifying and Resolving Conflicts

When you or Visio refresh data and a resulting conflict occurs, you can use the DataRecordset.GetAllRefreshConflicts method and the DataRecordset.GetMatchingRowsForRefreshConflict method to determine why the conflict arose. The GetAllRefreshConflicts method returns an array of shapes for which a conflict exists between data in the shape and data in the data-recordset row to which the shape is linked. To determine which data-recordset rows produced the conflict, you can then pass each of these shapes to the GetMatchingRowsForRefreshConflict method, which returns an array of rows that are in conflict.

Rows in the data recordset can conflict when two or more of them have identical primary keys, and may link to the same shape. When this occurs, GetMatchingRowsForRefreshConflict returns an array containing at least two row IDs.

Conflicts can also occur when a previously data-linked row from the data recordset is removed. When this occurs, the method returns an empty array.

To remove the conflict, pass the shape to the DataRecordset.RemoveRefreshConflict method, which removes the conflicting information from the current document.

Other Additions to the Visio Object Model

In addition to the new objects and members related to data connectivity, the Visio object model now includes several other new members that make it easier to apply theme effects and theme colors, to draw connections between shapes on the drawing page, and to accomplish several other tasks.

Applying Theme Colors and Theme Effects

You can get and set the theme colors and theme effects applied to the active document or page in your Visio drawing programmatically by using two new properties of the Page object, the Page.ThemeColors property and the Page.ThemeEffects property. You can apply any of the built-in Visio theme colors and theme effects. You can view them in the Theme – Colors task pane and the Theme - Effects task pane in the Visio UI. By moving your mouse over one of the themes in the task panes, you can determine the property value to assign to apply that theme.

You can also get these names programmatically by using the Document.GetThemeNames method and the Document.GetThemeNamesU method. These methods take as a parameter either the visTypeThemeColors enumerated value or the visTypeThemeEffects enumerated value from the VisThemeTypes enumeration. They return an array of theme names.

You can set theme colors and theme effects for a page by setting the Page.ThemeColors property value and the Page.ThemeEffects property value to one of the following:

  • A numeric value from the VisThemeColors enumeration or from the VisThemeEffects enumeration, for colors and effects, respectively

  • A string value equal to the theme name

  • A reference to a master, as explained in the next paragraph

Theme colors are actually masters of type visTypeThemeColorsMaster. Theme effects are masters of type visTypeThemeEffectsMaster. Theme colors masters and theme effects masters are like data graphic masters in that you ordinarily do not create instances of them.

Alternatively, you can create your own theme colors or theme effects and apply them by using the same properties. For sample code that shows how to create themes, see the sample "Customizing Themes" in the Code Samples Library in the Visio 2007 SDK.

Drawing Shape Connectors Programmatically

You can automatically draw connections between shapes on the drawing page while specifying the direction of the connection and, optionally, the connector. The following code example shows how to use the Shape.AutoConnect method to draw a connection between two flowchart shapes, a Decision shape and a Process shape, by using a third (Dynamic Connector) shape, all of which were added to an empty drawing page from the Basic Flowchart Shapes stencil.

Because the example calls the method on the Decision shape, Visio draws the connector from the Decision shape to the Process shape. Because we pass the method the enumerated value visAutoConnectDirRight (from the VisAutoConnectDir enumeration) as the required second parameter, Visio places the Process shape automatically to the right of the Decision shape on the drawing page, regardless of its previous location.

Public Sub AutoConnectShapes()
    Dim vsoShape1 As Visio.Shape
    Dim vsoShape2 As Visio.Shape
    Dim vsoConnectorShape As Visio.Shape

    Set vsoShape1 = Visio.ActivePage.Shapes("Decision")
    Set vsoShape2 = Visio.ActivePage.Shapes("Process")
    Set vsoConnectorShape = Visio.ActivePage.Shapes("Dynamic _
         connector")
    vsoShape1.AutoConnect vsoShape2, visAutoConnectDirRight, _
         vsoConnectorShape
End Sub

Other New Features of the Visio Object Model

Visio 2007 adds several other new members to the object model in the following categories:

  • Removing hidden information.

  • New document check-out and check-in methods.

  • New language settings properties.

  • New extensions to the MouseMove event. Visio 2007 also provides you the ability to filter the extensions to listen to only the ones you specify.

  • Miscellaneous application settings.

For more information about these new members, and for descriptions, see What's New for Developers in Visio 2007 (Part 2 of 2). The Visio 2007 SDK Code Samples Library provides sample code showing how to use many of these new members.

Conclusion

This article introduces the new features of interest to developers in Microsoft Office Visio 2007 and explains how to use them. Among the new features are features relating to data connectivity, linking and display, auto-connection of shapes, and color and effect themes. What's New for Developers in Visio 2007 (Part 2 of 2) is a reference list of all new Automation objects and members, and of new ShapeSheet cells and functions.

Additional Resources

For more information about existing members of the Visio object model and about the Visio ShapeSheet, see About the Microsoft Office Visio ShapeSheet Reference [Visio 2003 SDK Documentation]. For more code samples showing how to use the new data-related members of the Visio object model, download the Visio 2007: Software Development Kit.