Part 2: Writing the classes and methods that convert and export Visio 2010 diagrams to PowerPoint 2010

Summary:  The second article in a series of four articles about how to export Microsoft Visio 2010 shapes to Microsoft PowerPoint 2010. Part 2 discusses how to export Visio 2010 pages and diagrams to PowerPoint 2010, how to programmatically re-create a Visio diagram on a Microsoft PowerPoint 2010 slide, and how to read formatting values from the ShapeSheet of a Visio shape.

Applies to: Office 2010 | PowerPoint 2010 | SharePoint Server 2010 | Visio 2010 | Visio Premium 2010 | Visual Studio 2010

In this article
Creating the ThisAddIn Class
Creating the ShapeConversion Class
Looking Up PowerPoint Shape Conversion Values for Visio Shapes
Read the Other Articles in this Series

Published:  June 2012

Provided by:  Eric Schmidt, Microsoft Corporation

Contents

  • Creating the ThisAddIn Class

  • Creating the ShapeConversion Class

  • Looking Up PowerPoint Shape Conversion Values for Visio Shapes

  • Read the Other Articles in this Series

Download the code

Creating the ThisAddIn Class

The ThisAddIn class of the Exporting Visio 2010 Diagrams to PowerPoint 2010 add-in contains the code that iterates through the pages and shapes in the Visio document, creates a new PowerPoint application and slides, populates the PowerPoint slides with shapes, and creates connections between the shapes on the PowerPoint slide.

The ThisAddIn class uses both the Visio and the PowerPoint object models. The add-in also uses a MessageBox object to warn users about any exceptions the code raises. Therefore, you must import the Microsoft.Office.Interop.PowerPoint and System.Windows.Forms libraries to the ThisAddIn class.

At the top of the ThisAddIn.vb or ThisAddIn.cs file, add the following code, which imports the Microsoft.Office.Interop.PowerPoint and System.Windows.Forms libraries.

Imports PowerPoint = Microsoft.Office.Interop.PowerPoint
Imports Microsoft.Office.Core
Imports System.Windows.Forms
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Core;
using System.Windows.Forms;

Several methods of the ThisAddIn class must access the current Visio page or PowerPoint slide. Thus, the ThisAddIn class has two class fields:

  • visioPage, which is a Visio.Page object that represents the Visio page being exported

  • pptBlankSlide, which is a Slide object that represents the PowerPoint slide being created

In the declarations region of the ThisAddIn class, add the following code, which declares the class fields visioPage and pptBlankSlide.

' Declare a new pptBlankSlide as the PowerPoint slide.
Public pptBlankSlide As PowerPoint.Slide

' Declare a variable for the Visio page to be exported.
Public visioPage As Visio.Page
// Declare a new pptBlankSlide as the PowerPoint slide.
public PowerPoint.Slide pptBlankSlide;

// Declare a variable for the Visio page to be exported.
public Visio.Page visioPage;

The ExportPage and ExportAllPages methods of the ThisAddIn class begin executing the primary code of the add-in. The ExportPage method creates a new PowerPoint presentation that has a single slide, captures a reference to the object that is returned by the Visio Application.ActivePage property in the visioPage global variable, and calls the Main method of the ThisAddIn class. The ExportPage method creates a reference to a new Presentation object by calling the OpenPPTSession method. It instantiates the pptBlankSlide global variable by calling the AddPPTSlide method to create a new Slide object in the presentation.

The ExportAllPages method also creates a new Presentation object by calling the OpenPPTSession method. However, instead of getting a reference to the active page in the Visio document, the ExportAllPages method gets a reference to the Visio document and iterates through each page in the document. For each page, the method captures a reference to a new Slide object in the pptBlankSlide global variable and then calls the Main method of the ThisAddIn class.

Below the class fields in the ThisAddIn class in the ThisAddIn.vb or ThisAddIn.cs file, add the following code, which calls the OpenPPTSession method to create a Microsoft PowerPoint presentation, calls the AddPPTSlide method to create a Microsoft PowerPoint slide for each Visio page to be exported, and calls the Main.

Public Sub ExportPage()

    ' Create a new PowerPoint presentation that has a new slide.
    Dim pptPreso As PowerPoint.Presentation = OpenPPTSession()
    pptBlankSlide = AddPPTSlide(pptPreso)

    ' Export shapes on the Visio page to PowerPoint.
    visioPage = Application.ActivePage
    Main()
End Sub

Public Sub ExportAllPages()

    ' Create a new PowerPoint presentation.
    Dim pptPreso As PowerPoint.Presentation = OpenPPTSession()
    Dim visioDoc As Visio.Document = _
        Globals.ThisAddIn.Application.ActiveDocument
    Dim numPages = visioDoc.Pages.Count

    ' Iterate through each page in the Visio document.
    For x As Integer = 1 To numPages

        visioPage = visioDoc.Pages.Item(x)
        pptBlankSlide = AddPPTSlide(pptPreso)
        Main()
    Next
End Sub
public void ExportPage()
{
    // Create a new PowerPoint presentation that has a new slide.
    PowerPoint.Presentation pptPreso = OpenPPTSession();
    pptBlankSlide = AddPPTSlide(pptPreso);

    // Export shapes on the Visio page to PowerPoint.
    visioPage = Application.ActivePage;
    Main();
}

public void ExportAllPages()
{
    // Create a new PowerPoint presentation.
    PowerPoint.Presentation pptPreso = OpenPPTSession();
    Visio.Document visioDoc = 
        Globals.ThisAddIn.Application.ActiveDocument;
    int numPages = visioDoc.Pages.Count;

    // Iterate through each page in the Visio document.
    for (int x = 1; x <= numPages; x++)
    {
        visioPage = visioDoc.Pages.get_ItemU(x);
        pptBlankSlide = AddPPTSlide(pptPreso);
        Main();
    }
}

The Main method of the ThisAddIn class executes two loops in sequence. The first loop iterates through each Visio.Shape object in the Visio.Shapes collection of the visioPage object and creates a corresponding Shape in the Shapes collection of the pptBlankSlide object. The second loop iterates through each active connection on the Visio page and attaches connector shapes on the PowerPoint slide accordingly. Also note that the method is wrapped in a Try...Catch block, where any error messages raised are displayed by using the Show(String) method.

Before the method executes any other code, it suspends the Diagram Services that are enabled for the current Visio diagram. The Diagram Services in Visio 2010 include the Structured Diagram behaviors that govern Container shapes (among other things). If the Structured Diagram behaviors are enabled while the first loop of the Main method executes, the add-in exports Container shapes with the shapes that they contain and then export the contained shapes, duplicating the shapes. If Diagram Services are disabled, the first loop treats a Container shape and the shapes that it contains as separate and individual shapes, and exports them each individually. Thus, the method sets the Document.DiagramServicesEnabled property to visServiceNone to disable these behaviors and then resets the property after the code has finished running.

Note

It is a best practice to save the current value of the Document.DiagramServicesEnabled property before you change it, and then resetting the property to its previous value after your code runs.

The first loop of the Main method is a For Each block. The loop iterates through each Visio.Shape object in the Visio.Shapes collection of the visioPage object. Each iteration creates a new ShapeConversion object by using the constructor method of that class, which takes a Visio.Shape object as an argument. The method then uses a Switch Case block (with ShapeConversion.pptShapeType property as the test expression) to determine what method of the ThisAddIn class to use to construct the new PowerPoint shape. The ShapeConversion.pptShapeType property returns an integer value that corresponds to the constant from the MsoAutoShapeType enumeration of the new shape to create. The property can also return a value of 0 or -1, where a 0 indicates that the Visio shape is a dynamic connector, and a value of -1 indicates that the Visio shape does not have an equivalent in PowerPoint.

For the second loop, the method first gets the Connects collection that is associated with the visioPage object. The Connects collection contains a reference to each active connection point on the Visio page. If the Connects collection has any items, the method uses a For Next block to iterate through the collection. In each iteration of this loop, the method retrieves a Connect object from the Connects collection, and then calls the ConnectShapes method of the ThisAddIn class, which glues connectors to shapes on the PowerPoint slide (pptBlankSlide object).

Below the definition of the AddPPTSlide method of the ThisAddIn class in the ThisAddIn.vb or ThisAddIn.cs file, add the following code, which iterates through all the shapes on a page in the Visio diagram, and then iterates through each connection on the Visio page.

Public Sub Main()

    Try
        ' Save the value of the DiagramServicesEnabled property 
        ' and turn Diagram Services off.
        Dim diagramSvcs As Integer = visioPage.Document.DiagramServicesEnabled
        visioPage.Document.DiagramServicesEnabled = _
            CInt(Visio.VisDiagramServices.visServiceNone)

            ' Defines visioShapes as the shapes collection for visioPage,
            ' vsoShape as the Visio shape being converted, 
            ' and vsoShpCount as the count of shapes on the page.
            Dim visioShapes As Visio.Shapes = visioPage.Shapes
            Dim vsoShape As Visio.Shape
            Dim vsoShpCount As Integer = visioShapes.Count

            For x = 1 To vsoShpCount

                vsoShape = visioShapes(x)
                Dim currShapeConversion As ShapeConversion = _
                    New ShapeConversion(vsoShape)

                ' Determine how to convert currVisioShape.
                Select Case currShapeConversion.pptShapeType
                    Case 0
                        ' The shape is a connector; create a PowerPoint connector.
                        ConstructPPTConnector(currShapeConversion)

                    Case -1
                        ' The shape is not in ShapeConversion.xml; 
                        ' copy the Visio shape to PowerPoint as an enhanced metafile.
                        CopyPasteVisioToPPT(x, currShapeConversion)

                    Case Else
                        ' Create a PowerPoint analog of the Visio shape.
                        ConstructPPTShape(currShapeConversion)

                End Select
            Next x
        ' Get the connections on the Visio page.
        Dim visConnects As Visio.Connects = visioPage.Connects
        Dim cnctCount As Integer = visConnects.Count

        ' Check to see whether there are connections on the page.
        If cnctCount > 0 Then

            ' Iterate through the connection points on the Visio page. 
            For c As Integer = 1 To cnctCount

                ' Connect the matching connector and shape on the PowerPoint slide.
                ConnectShapes(visConnects(c))

            Next c
        End If

        ' Restore the previous Diagram Services setting.
        visioPage.Document.DiagramServicesEnabled = diagramSvcs

    Catch ex As Exception
        MessageBox.Show(ex.Message)
    End Try
End Sub
public void Main()
{
    try
    {
        // Save the value of the DiagramServicesEnabled property 
        // and turn services off.
        int diagramSvcs = visioPage.Document.DiagramServicesEnabled;
        visioPage.Document.DiagramServicesEnabled = 
            Convert.ToInt32(Visio.VisDiagramServices.visServiceNone);

        // Defines visioShapes as the shapes collection for visioPage,
        // vsoShape as the Visio shape being converted, 
        // and vsoShpCount as the count of shapes on the page.
        Visio.Shapes visioShapes = visioPage.Shapes;
        int vsoShpCount = visioShapes.Count + 1;
        Visio.Shape vsoShape;

        // Loop through each shape on the visioPage.
        for (int x = 1; x < vsoShpCount; x++) { 
                
            vsoShape = visioShapes[x];
            ShapeConversion currShapeConversion = 
                new ShapeConversion(vsoShape);
                    
            // Determine how to convert currVisioShape.
            switch (currShapeConversion.pptShapeType)
            {
                case 0:
                    // The shape is a connector; create a PowerPoint connector.
                    ConstructPPTConnector(currShapeConversion);
                    break;

                case -1:
                    // The shape is not in ShapeConversion.xml; 
                    // copy the Visio shape to PowerPoint as an enhanced metafile.
                    CopyPasteVisioToPPT(x, currShapeConversion);
                    break;

                default:
                    // Create a PowerPoint analog of the Visio shape.
                    ConstructPPTShape(currShapeConversion);
                    break;
            }
        }

        // Get the connections on the Visio page.
        Visio.Connects visConnects = visioPage.Connects;
        int cnctCount = visConnects.Count;

        // Check to see whether there are connections on the page.
        if (cnctCount > 0)
        {

            // Iterate through the connection points on the Visio page. 
            foreach (Visio.Connect visConnect in visConnects)
            {

                // Connect the matching connector and shape on the PowerPoint slide.
                ConnectShapes(visConnect);
            }
        }

        // Restore the previous Diagram Services setting.
        visioPage.Document.DiagramServicesEnabled = diagramSvcs;

    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
}

Creating the ShapeConversion Class

At the core of the Exporting Visio 2010 Diagrams to PowerPoint 2010add-in is the ShapeConversion class, which enables the add-in to get and store data from a Visio shape while encapsulating the necessary conversion processes. The ShapeConversion class performs three major tasks:

  1. It gets the text, name, spatial, and formatting data from the Visio.Shape object.

  2. It converts the data returned from the ShapeSheet of the Visio.Shape object to values that can be used to create a new Shape object.

  3. It stores the data so that the methods of the ThisAddIn class can get the values that they need from a single object.

Create the ShapeConversion class before you add the remaining methods of the ThisAddIn class. This enables you to use IntelliSense to show the exposed properties of the ShapeConversion class while you write those methods. Use the following procedure to add a new class item to the Visual Studio 2010 project to contain the code for the ShapeConversion class.

To add a new class item to the project

  1. In Solution Explorer, right-click the project name (ExportToPPT), point to Add, and then click New Item.

  2. Select Class.

  3. Type a name for the item ("ShapeConversion.vb" or "ShapeConversion.cs") and then click Add.

  4. In Solution Explorer, double-click the new class.

The ShapeConversion class uses an embedded XML resource to look up some of the shape conversion values (see "Looking up PowerPoint Shape Conversion Values for Visio Shapes" in Part 1: Setting up the Visio solution and customizing the ribbon). You must import several libraries to this class to use this code.

At the top of the ShapeConversion.vb or ShapeConversion.cs file, add the following using directives to import the System.Xml, System.Xml.Linq, System.Reflection, System.IO, and Microsoft.Office.Interop.Visio libraries.

Imports System.Xml
Imports System.Xml.Linq
Imports System.Reflection
Imports System.IO
Imports Visio = Microsoft.Office.Interop.Visio
using System.Xml;
using System.Xml.Linq;
using System.Reflection;
using System.IO;
using Visio = Microsoft.Office.Interop.Visio;

The ShapeConversion class exposes many read-only properties to the calling code. These class properties are exposed by using the Property keyword and are set by referencing Private class fields. The ShapeConversion class in the full-version of the Exporting Visio 2010 Diagrams to PowerPoint 2010 add-in that is available from the Samples Gallery exposes many more properties than the code samples do in this article.

Table 1 displays the properties that the ShapeConversion class exposes.

Table 1. ShapeConversion class properties exposed in the "Exporting Visio 2010 Diagrams to PowerPoint 2010" add-in

Class property name

Class field

Return value

Description

Included in article?

pptShapeType

shapeType

Integer

A constant from the MsoAutoShapeType enumeration.

Yes

pptShapeName

shapeName

String

The name of the Visio shape.

Yes

pptShapeWidth

shapeWidth

Single

The width, in points, of the shape (72 points equals 1 inch).

Yes

pptShapeHeight

shapeHeight

Single

The height, in points, of the shape (72 points equals 1 inch).

Yes

pptShapeLeft

shapeLeft

Single

The distance, in points, of the left edge of the shape from the left edge of the slide (72 points equals 1 inch).

Yes

pptShapeTop

shapeTop

Single

The distance, in points, of the top edge of the shape from the top edge of the slide (72 points equals 1 inch).

Yes

pptShapeRotation

shapeRotation

Single

The amount of rotation, in degrees, of the shape (0 degrees corresponds to the top edge of the shape being closest to the top of the slide, and then the numbers increase as the shape rotates clockwise).

No

pptShapeText

shapeText

String

The text from the Visio shape.

Yes

hasText

shapeHasText

Boolean

Specifies whether the shape has text.

No

pptShapeTextColor

shapeTextColor

Integer

The RGB value, as a PaletteEntry, of the color of the text in the shape.

No

pptShapeTextFont

shapeTextFont

String

The name of the font of the text in the shape.

No

pptShapeTextFontSize

shapeTextFontSize

Single

The size of the font of the text in the shape.

No

pptShapeTextHAlign

shapeTextHAlign

Integer

A constant from the PpParagraphAlignment enumeration.

No

pptShapeTextVAlign

shapeTextVAlign

Integer

A constant from the MsoVerticalAnchor enumeration.

No

pptShapeTextOrientation

shapeTextOrient

Integer

A constant from the MsoTextOrientation enumeration.

No

pptShapeTextOverlayX

shapeTextOverlayX

Integer

The distance, in points, from the left edge of the slide to a shape's text box (72 points equals 1 inch).

No

pptShapeTextOverlayY

shapeTextOverlayY

Integer

The distance, in points, from the top edge of the slide to a shape's text box (72 points equals 1 inch).

No

pptShapeTextOverlayWidth

shapeTextOverlayWidth

Integer

The width, in points, of a shape's text box (72 points equals 1 inch).

No

pptShapeTextOverlayHeight

shapeTextOverlayHeight

Integer

The height, in points, of a shape's text box (72 points equals an inch).

No

pptShapeFillColor

shapeFillColor

Integer

The RGB value, as a PaletteEntry, of the color of the shape.

Yes

pptShapeFillTrans

shapeFillTrans

Single

The percentage of transparency of the shape's fill color.

No

pptShapeLineColor

shapeLineColor

Integer

The RGB value, as a PaletteEntry, of the color of the border of a shape.

No

pptShapeLineWeight

shapeLineWeight

Single

The weight of the border of a shape.

No

pptShapeLinePattern

shapeLinePattern

Integer

A constant from the MsoLineDashStyle enumeration.

No

pptShapeLineBeginArrow

shapeLineBeginArrow

Integer

A constant from the MsoArrowheadStyle enumeration. This property is set only for one-dimensional shapes (that is, connectors).

No

pptShapeLineEndArrow

shapeLineEndArrow

Integer

A constant from the MsoArrowheadStyle enumeration. This property is set only for one-dimensional shapes (that is, connectors).

No

pptConnectorBeginX

connectorBeginX

Integer

The distance, in points, from the left edge of the slide to the point that a connector originates from (72 points equals 1 inch).

Yes

pptConnectorBeginY

connectorBeginY

Integer

The distance, in points, from the top edge of the slide to the point that connector originates from (72 points equals 1 inch).

Yes

pptConnectorEndX

connectorEndX

Integer

The distance, in points, from the left edge of the slide to the point where a connector ends (72 points equals one inch).

Yes

pptConnectorEndY

connectorEndY

Integer

The distance, in points, from the top edge of the slide to the point where a connector ends (72 points equals 1 inch).

Yes

pptConnectorType

connectorType

Integer

A constant from the MsoConnectorType enumeration. This property is set only for one-dimensional shapes (that is, connectors).

No

pptShapeShadow

shapeShadow

Boolean

Specifies whether the shape has a shadow.

No

pptShapeShadowColor

shapeShadowColor

Integer

The RGB value, as a PaletteEntry, of the color of the shadow of a shape.

No

pptShapeShadowTrans

shapeShadowTrans

Single

The percentage of transparency of the shadow of a shape.

No

pptShapeShadowOffsetX

shapeShadowOffsetX

Integer

The distance, in points, that a shadow is displaced to the right or left of a shape, where positive values move the shadow to the right of a shape.

No

pptShapeShadowOffsetY

shapeShadowOffsetY

Integer

The distance, in points, that a shadow is displaced above or below a shape, where positive values move the shadow below a shape.

No

pptShapeShadowSize

shapeShadowSize

Single

The size of the shadow as a percentage of the size of a shape.

No

In the declarations area of the ShapeConversion class in the ShapeConversion.vb or ShapeConversion.cs file, add the following code, which creates the class properties for the ShapeConversion class.

' Declare private fields for setting class properties.
Private shapeType As Integer
Private shapeName As String
Private shapeWidth As Integer
Private shapeHeight As Integer
Private shapeLeft As Integer
Private shapeTop As Integer
Private shapeText As String
Private shapeFillColor As Integer
Private connectorBeginX As Short
Private connectorBeginY As Short
Private connectorEndX As Short
Private connectorEndY As Short

' Declare ShapeConversion class properties.
ReadOnly Property pptShapeType() As Integer
    Get
        pptShapeType = shapeType
    End Get
End Property
ReadOnly Property pptShapeName() As String
    Get
        pptShapeName = shapeName
    End Get
End Property
ReadOnly Property pptShapeWidth() As Single
    Get
        pptShapeWidth = shapeWidth
    End Get
End Property
ReadOnly Property pptShapeHeight() As Single
    Get
        pptShapeHeight = shapeHeight
    End Get
End Property
ReadOnly Property pptShapeLeft() As Single
     Get
       pptShapeLeft = shapeLeft
    End Get
End Property
ReadOnly Property pptShapeTop() As Single
    Get
        pptShapeTop = shapeTop
    End Get
End Property
ReadOnly Property pptShapeText() As String
    Get
        pptShapeText = shapeText
    End Get
End Property
ReadOnly Property pptShapeFillColor As Integer
    Get
        pptShapeFillColor = shapeFillColor
    End Get
End Property
ReadOnly Property pptConnectorBeginX As Short
    Get
        pptConnectorBeginX = connectorBeginX
    End Get
End Property
ReadOnly Property pptConnectorBeginY As Short
    Get
        pptConnectorBeginY = connectorBeginY
    End Get
End Property
ReadOnly Property pptConnectorEndX As Short
    Get
        pptConnectorEndX = connectorEndX
    End Get
End Property
ReadOnly Property pptConnectorEndY As Short
    Get
        pptConnectorEndY = connectorEndY
    End Get
End Property
// Declare private fields for setting class properties.
private int shapeType;
private string shapeName;
private int shapeWidth;
private int shapeHeight;
private int shapeLeft;
private int shapeTop;
private string shapeText;
private int shapeFillColor;
private short connectorBeginX;
private short connectorBeginY;
private short connectorEndX;
private short connectorEndY;

// Declare ShapeConversion class properties.
public int pptShapeType {
    get {
        return shapeType;
    }
}
public string pptShapeName {
    get { 
        return shapeName; 
    }
}
public int pptShapeWidth {
    get { 
        return shapeWidth; 
    }
}
public int pptShapeHeight {
    get { 
        return shapeHeight; 
    }
}
public int pptShapeLeft {
    get { 
        return shapeLeft; 
    }
}
public int pptShapeTop {
    get { 
        return shapeTop; 
    }
}
public string pptShapeText {
    get { 
        return shapeText; 
    }
}
public int pptShapeFillColor {
    get { 
         return shapeFillColor; 
    }
}
public short pptConnectorBeginX {
    get { 
        return connectorBeginX; 
    }
}
public short pptConnectorBeginY {
    get { 
        return connectorBeginY; 
    }
}
public short pptConnectorEndX {
    get { 
        return connectorEndX; 
    }
}
public short pptConnectorEndY {
    get { 
        return connectorEndY; 
    }
}

The ShapeConversion class uses three private class fields for constructing an object: visioShape, visioPageHeight, and cf. These fields must be accessible by all the internal methods of the ShapeConversion class.

The visioShape variable captures a reference to the curShape object that is passed as an argument into the constructor method. All the methods in the class reference that Visio.Shape object and no other shape, so you do not have to include a Visio.Shape object as a required parameter for all the internal methods.

The visioPageHeight and cf variables are used for transposing the spatial relationships of the Visio shape to the new shape on the PowerPoint slide. Visio uses the bottom-left corner of the page as the point of origin for shapes on the drawing canvas, with values increasing as the shape's distance towards the top and right edges of the canvas increases. In contrast, PowerPoint references the location of a shape on the slide in points (72 per inch) from the top-left corner of a slide, with values increasing as the shape's distance towards the bottom and right edges of the slide increases. Thus, the ShapeConversion class uses the visioPageHeight field to calculate the location of the visioShape object from the top-left corner of the Visio drawing page. The cf variable represents the conversion factor between Visio inches and PowerPoint points.

Note

When set to a value of 72 points per inch, the cf variable creates an exact 1-inch to 1-inch mapping between the Visio shape on the Visio page and the PowerPoint shape on the PowerPoint slide. Shapes that are more than 7.5 inches below or 10 inches to the right of the top-left corner of the Visio drawing page are transposed off the edge of a default PowerPoint slide. If you prefer, you can scale the new PowerPoint shapes by changing the value of the cf variable. (For example, you could set the value to of the cf variable equal to 72 * (7.5 / visioPageHeight), which scales all the shapes to a ratio of the height of the PowerPoint slide against the height of the Visio page.).

As shown in the Main method of the ThisAddIn class, the constructor method for the ShapeConversion class has a single parameter, curShape, which takes a Visio.Shape object as an argument. The method then captures the Shape.Name property of the Visio shape in the shapeName variable. This property of the Visio shape is a unique value for each shape on the page and is usually derived from the master shape that is used to create the shape. After the constructor method captures references into the global variables, it calls the internal LookupVisioToPowerPoint method to set the value of the shapeType variable and, by extension, the pptShapeType class property. (For more information about the LookUpVisioToPowerPoint method, see the section, "Looking up PowerPoint Shape Conversion Values for Visio Shapes" in Part 1: Setting up the Visio solution and customizing the ribbon.

Next, the constructor method gets the spatial relationships of the Visio shape on the page. First, the method checks whether the visioShape object is a one-dimensional shape (a connector or a line). If the visioShape object is a one-dimensional shape, the method gets the beginning point and endpoint values of the shape by using the internal helper function GetVisioSingleFromCell. If the shape is not one-dimensional, the method gets the width, height, distance from the left edge of the page, and the distance from the top edge of the page for the visioShape object by using GetVisioSingleFromCell. In addition, if the visioShape object is not one-dimensional, the method gets the fill color of the shape, as an integer, by using the GetVisioColorFromCell method.

Lastly, the constructor method checks whether the visioShape object has any text associated with it. If the visioShape object has no text, the method sets the shapeText variable to null. Otherwise, the method stores the text as an unformatted string in the shapeText variable.

Below the class properties of the ShapeConversion class in the ShapeConversion.vb or ShapeConversion.cs file, add the following code, which creates the three class fields and defines the constructor method for the ShapeConversion class.

' Declare class fields for object construction.
Dim visioShape As Visio.Shape
Dim visioPageHeight As Single
Dim cf As Integer

Sub New(ByVal curShape As Visio.Shape)

    ' Set the global variables.
    visioShape = curShape
    visioPageHeight = visioShape.ContainingPage.PageSheet. _
        Cells("PageHeight").Result(vbSingle)
    cf = 72

    ' Record the visioShape name
    ' and then look up the equivalent PowerPoint shape.
    shapeName = visioShape.Name
    shapeType = LookupVisioToPowerPoint()

    ' Check whether the shape is 1-D (a connector).
    If Not (visioShape.OneD = 0) Then

        ' Set the begin and end points of the shape from the Visio connector.
        connectorBeginX = CShort(cf * GetVisioSingleFromCell("BeginX"))
        connectorBeginY = CShort(cf * (visioPageHeight - _
            GetVisioSingleFromCell("BeginY")))
        connectorEndX = CShort(cf * GetVisioSingleFromCell("EndX"))
        connectorEndY = CShort(cf * (visioPageHeight - _
            GetVisioSingleFromCell("EndY")))

    Else
        ' Get and set the shape width and height.
        If CBool(visioShape.CellExists("Width", 1)) Then
            shapeWidth = cf * GetVisioSingleFromCell("Width")
            shapeHeight = cf * GetVisioSingleFromCell("Height")
        Else
            shapeWidth = cf * GetVisioSingleFromCell("User.DefaultWidth")
            shapeHeight = cf * GetVisioSingleFromCell("User.DefaultHeight")
        End If

        ' Get the Visio shape's relationship to the top-left corner of the page.
        shapeLeft = (cf * GetVisioSingleFromCell("PinX")) - (0.5 * shapeWidth)
        shapeTop = (cf * (visioPageHeight - GetVisioSingleFromCell("PinY"))) _
            - (0.5 * shapeHeight)

        ' Get the color of the Visio shape.
        shapeFillColor = GetVisioColorFromCell("FillBkgnd")
    End If

    ' Check whether the shape has any text.
    If visioShape.Characters.Text = vbNullString Then
        shapeText = vbNullString
    Else
        ' Get the shape's text.
        shapeText = visioShape.Text
    End If

End Sub
// Declare global variables for object construction.
private Visio.Shape visioShape;
private double visioPageHeight;
private int cf;

public ShapeConversion(Visio.Shape curShape) {

    // Set the global variables.
    visioShape = curShape;
    visioPageHeight = visioShape.ContainingPage.PageSheet.
        get_Cells("PageHeight").get_Result(Visio.VisUnitCodes.visInches);
    cf = 72;

    // Record the visioShape name 
    // and then look up the equivalent PowerPoint shape.
    shapeName = visioShape.Name;
    shapeType = LookupVisioToPowerPoint();

    // Check whether the shape is 1-D (a connector).
    if (!(visioShape.OneD == 0)) {

        // Set the begin and end points of the shape from the Visio connector.
        connectorBeginX = (short)(cf * GetVisioSingleFromCell("BeginX"));
        connectorBeginY = (short)(cf * (visioPageHeight - 
            GetVisioSingleFromCell("BeginY")));
        connectorEndX = (short)(cf * GetVisioSingleFromCell("EndX"));
        connectorEndY = (short)(cf * (visioPageHeight - 
            GetVisioSingleFromCell("EndY")));

    } else {

        // Get and set the shape width and height.
        if (Convert.ToBoolean(visioShape.get_CellExists("Width", 1))) {
            shapeWidth = (int)(cf * GetVisioSingleFromCell("Width"));
            shapeHeight = (int)(cf * GetVisioSingleFromCell("Height"));
        } else {
            shapeWidth = (int)(cf * 
                GetVisioSingleFromCell("User.DefaultWidth"));
            shapeHeight = (int)(cf * 
                GetVisioSingleFromCell("User.DefaultHeight"));
        }

        // Get the Visio shape's relationship to the top-left corner of the page.
        shapeLeft = (int)((cf * GetVisioSingleFromCell("PinX")) - 
            (0.5 * shapeWidth));
        shapeTop = (int)((cf * (visioPageHeight - 
            GetVisioSingleFromCell("PinY"))) - (0.5 * shapeHeight));

        // Get the color of the Visio shape.
        shapeFillColor = GetVisioColorFromCell("FillBkgnd");
    }

    // Check whether the shape has any text.
    if (visioShape.Characters.Text == "") {
        shapeText = null;

    } else {
        // Get the shape's text.
        shapeText = visioShape.Text;
    }
}

As you can see, the constructor method of the ShapeConversion class uses two internal helper methods, GetVisioSingleFromCell and GetVisioColorFromCell, to get values from the ShapeSheet of the visioShape object. Both methods take a string as an argument that determines the ShapeSheet cell to query, get the value from a cell in the ShapeSheet, and then return a value of the appropriate data type.

The GetVisioSingleFromCell method gets a value from the visioShape object by using the Cell.Result property, passing in the visInches constant from the VisUnitCodes enumeration for the UnitsNameOrCode parameter. The method returns the value from the cell to the calling code as a double-precision floating-point number.

The GetVisioColorFromCell method also uses the Cell.Result property to get a value from the ShapeSheet, but instead, passes in the visNoCast constant from the VisUnitCodes enumeration. This method then uses the value that is returned from the cell (returned as a double-precision floating-point number), converts the number to an integer, and then uses the integer as the ID of a Color object from the Colors collection of the Visio document that is associated with the visioShape object. The method uses the Color.PaletteEntry property to get a single integer that represents the RGB value of the Color object and returns that integer to the calling code.

Below the constructor method of the ShapeConversion class in the ShapeConversion.vb or ShapeConversion.cs file, add the following code, which creates the two helper methods that get data from the ShapeSheet of a Visio shape.

Private Function GetVisioSingleFromCell(ByVal cellName As String) As Single

    Dim visioCell As Visio.Cell

    ' Get data from a Visio cell that contains a single data type.
    visioCell = visioShape.Cells(cellName)
    Return visioCell.Result(Visio.VisUnitCodes.visInches)

End Function

Private Function GetVisioColorFromCell(ByVal cellName As String) As Integer

    Dim visioCell As Visio.Cell
    Dim visioColorValue As Integer
    Dim visioColor As Visio.Color

    ' Get data from a Visio cell that contains color settings. 
    visioCell = visioShape.Cells(cellName)
    visioColorValue = visioCell.Result(Visio.VisUnitCodes.visNoCast)

    ' Get a Visio.Color object from the document 
    ' and return a PaletteEntry.
    visioColor = visioShape.Document.Colors(CInt(visioColorValue))
    Return visioColor.PaletteEntry

End Function
private double GetVisioSingleFromCell(string cellName)
{
    Visio.Cell visioCell;

    // Get data from a Visio cell that contains a single data type.
    visioCell = visioShape.get_Cells(cellName);
    return visioCell.get_Result(Visio.VisUnitCodes.visInches);
}

private int GetVisioColorFromCell(string cellName)
{
    Visio.Cell visioCell;
    Visio.Color vsoColor;

    // Get data from a Visio cell that contains color settings as a string.
    visioCell = visioShape.get_Cells(cellName);
    double visioColorNum = visioCell.get_Result(Visio.VisUnitCodes.visNoCast);

    // Get a Visio.Color object from the document 
    // and return a PaletteEntry.
    vsoColor = visioShape.Document.Colors[(int)visioColorNum];
    return vsoColor.PaletteEntry;
}

Looking Up PowerPoint Shape Conversion Values for Visio Shapes

One of the most difficult issues to address when you create a project like the Exporting Visio 2010 Diagrams to PowerPoint 2010 add-in is to determine how to store the data for the core lookup function. The add-in must contain a data source that matches Visio shape names (as strings) to integer values. There are many options available to store your data; for example, you could create a dictionary object at run time, integrate a SQL database into your project, or even define an enumeration to map the strings to integer values. Before you select a method to store data, first consider the performance and memory cost of any choice that you make.

The Exporting Visio 2010 Diagrams to PowerPoint 2010 add-in uses a simple XML document to store the data that matches Visio shapes to the built-in shapes in PowerPoint. The XML data source is lightweight, requires little additional code to query for values, and is easy to package into the add-in. To manipulate the XML data source, you could use the Document Object Model (DOM), but the add-in uses LINQ to XML as a quick and lightweight technique to retrieve data from the data source.

Use the following procedure to add an XML item to your Visual Studio 2010 project:

To add an XML item to your project

  1. In Solution Explorer, right-click the project name (ExportToPPT), point to Add, and then click New Item.

  2. Select XML File.

  3. Type a name for the item (for example, ShapeConversion.xml), and then click Add.

  4. In Solution Explorer, right-click the project name (ExportToPPT), and then click Properties.

  5. Click Resources.

  6. From Solution Explorer, drag the XML file (ShapeConversion.xml) onto the Resources design surface.

  7. Also in Solution Explorer, right-click the XML file (ShapeConversion.xml) and then click Properties.

  8. In the Properties window, set the Build Action property to Embedded Resource.

The ShapeConversion.xml document stores the names of shapes from a few built-in Visio stencils, together with the integer values that represent PowerPoint shapes. The root node of the XML document, ShapeConversion, includes Shape child nodes that represent Visio shapes that can be converted. The Shape elements include the name attribute, which specifies the name of the Visio master shape that is represented by the element, and the stencil attribute, which specifies the built-in stencil that contains the shape. Each Shape element contains a single child node, the PPTShape element. The PPTShape element is a simple type that has a single attribute, shapetype, which corresponds to a constant from the MsoAutoShapeType enumeration. The constant represents a shape in PowerPoint that is similar in both visual design and meaning to the Visio shape referenced in the Shape element. The content included in the PPTShape element is the integer value of the constant from the MsoAutoShapeType enumeration set as the value for the shapetype attribute.

The full version of Exporting Visio 2010 Diagrams to PowerPoint 2010 add-in also converts shapes from several other built-in Visio stencils, including the Organization Chart Shapes (US units) stencil (ORGCH_U.VSS), the Basic Shapes (US units) stencil (BASIC_U.VSS), and the Blocks (US units) stencil (BLOCK_U.VSS). Although the data source for the add-in stores the data for several conversions, the data in the add-in does not contain all built-in stencils. Table 2 displays the shapes that are included in the Exporting Visio 2010 Diagrams to PowerPoint 2010 add-in shape conversion data.

Table 2. Visio and PowerPoint shapes stored in the ShapeConversion.xml data

Visio shape name

Visio stencil

MsoAutoshapeType constant

MsoAutoshapeType integer value

Process

BASFLO_U.VSS

msoShapeFlowchartProcess

61

Decision

BASFLO_U.VSS

msoShapeFlowchartDecision

63

Subprocess

BASFLO_U.VSS

msoShapeFlowchartPredefinedProcess

65

Custom 3

BASFLO_U.VSS

msoShapeFlowchartCard

75

On-page reference

BASFLO_U.VSS

msoShapeFlowchartConnector

73

Data

BASFLO_U.VSS

msoShapeFlowchartData

64

Database

BASFLO_U.VSS

msoShapeFlowchartDirectAccessStorage

87

Document

BASFLO_U.VSS

msoShapeFlowchartDocument

67

Custom 1

BASFLO_U.VSS

msoShapeFlowchartManualInput

71

Custom 2

BASFLO_U.VSS

msoShapeFlowchartManualOperation

72

Off-page reference

BASFLO_U.VSS

msoShapeFlowchartOffpageConnector

74

Custom 4

BASFLO_U.VSS

msoShapeFlowchartPreparation

70

External Data

BASFLO_U.VSS

msoShapeFlowchartStoredData

83

Start/End

BASFLO_U.VSS

msoShapeFlowchartTerminator

69

Executive

ORGCH_U.VSS

msoShapeRectangle

1

Manager

ORGCH_U.VSS

msoShapeRectangle

1

Position

ORGCH_U.VSS

msoShapeRectangle

1

Vacancy

ORGCH_U.VSS

msoShapeRectangle

1

Consultant

ORGCH_U.VSS

msoShapeRectangle

1

Assistant

ORGCH_U.VSS

msoShapeRectangle

1

Rectangle

BASIC_U.VSS

msoShapeRectangle

1

Square

BASIC_U.VSS

msoShapeRectangle

1

Ellipse

BASIC_U.VSS

msoShapeOval

9

Circle

BASIC_U.VSS

msoShapeOval

9

Rounded rectangle

BASIC_U.VSS

msoShapeRoundedRectangle

5

Triangle

BASIC_U.VSS

msoShapeIsoscelesTriangle

7

Pentagon

BASIC_U.VSS

msoShapePentagon

51

Hexagon

BASIC_U.VSS

msoShapeHexagon

10

Heptagon

BASIC_U.VSS

msoShapeHeptagon

145

Octagon

BASIC_U.VSS

msoShapeOctagon

6

Star 5

BASIC_U.VSS

msoShape5pointStar

92

Star 6

BASIC_U.VSS

msoShape6pointStar

147

Star 7

BASIC_U.VSS

msoShape7pointStar

148

Right triangle

BASIC_U.VSS

msoShapeRightTriangle

8

Rounded square

BASIC_U.VSS

msoShapeRoundedRectangle

5

Box

BLOCK_U.VSS

msoShapeRectangle

1

Diamond

BLOCK_U.VSS

msoShapeDiamond

4

In the ShapeConversion.xml file, replace the default XML with the following XML, which stores the names from the Basic Flowchart Shapes (US units) stencil and constants from the MsoAutoShapeType enumeration.

<?xml version="1.0" encoding="utf-8" ?>
<!-- Visio Shapes included in this data are from the 
    Basic Flowchart Shapes (BASFLO_U.VSS) stencil. -->
<ShapeConversion>
  <Shape name="Custom 3" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartCard">75</PPTShape>
  </Shape>
  <Shape name="On-page reference" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartConnector">73</PPTShape>
  </Shape>
  <Shape name="Data" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartData">64</PPTShape>
  </Shape>
  <Shape name="Decision" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartDecision">63</PPTShape>
  </Shape>
  <Shape name="Database" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartDirectAccessStorage">87</PPTShape>
  </Shape>
  <Shape name="Document" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartDocument">67</PPTShape>
  </Shape>
  <Shape name="Custom 1" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartManualInput">71</PPTShape>
  </Shape>
  <Shape name="Custom 2" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartManualOperation">72</PPTShape>
  </Shape>
  <Shape name="Off-page reference" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartOffpageConnector">74</PPTShape>
  </Shape>
  <Shape name="Subprocess" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartPredefinedProcess">65</PPTShape>
  </Shape>
  <Shape name="Custom 4" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartPreparation">70</PPTShape>
  </Shape>
  <Shape name="Process" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartProcess">61</PPTShape>
  </Shape>
  <Shape name="External Data" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartStoredData">83</PPTShape>
  </Shape>
  <Shape name="Start/End" stencil="BASFLO_U.VSS">
    <PPTShape Shapetype="msoShapeFlowchartTerminator">69</PPTShape>
  </Shape>
</ShapeConversion>

In the ShapeConversion class code, the LookupVisioToPowerPoint method loads the ShapeConversion.xml document, queries the XML by using the value of the shapeName class field against the data that is stored in the XML, and then returns an integer value to the calling code.

Before the method opens the XML document and compares values, it must first change the shapeName variable to a string value that it can use. When a shape is added to the drawing canvas in Visio, it is assigned a unique name (on that page) based on the name of its master shape. The first shape from a specific master on the drawing page shares the name of the master it is derived from. Each subsequent shape from that master has a name in the format Master.#, where the number increases with each shape that is added to the page. This unique value can be accessed through the Shape.Name property. Because the method queries the XML data source using the name of the Visio master shape, the value of the Shape.Name property of the Visio.Shape object must be parsed to get the string that corresponds to that name. The LookupVisioToPowerPoint method takes the name of the visioShape object (as the shapeName field), converts the string to a string array by using a period (".") as a delimiter, and then stores the value of the first item in that array in the shapeMaster variable.

Note

The Visio.Shape object includes a Shape.Master property that returns the Master object from which that shape is derived. However, not all Visio shapes have masters. For example, calling the Shape.Master property on a Visio.Shape object that represents a drawing guide or a shape that was created by using the drawing tools ("Sheet") raises an exception.

Next, the LookupVisioToPowerPoint method checks whether the shapeMaster string represents a Dynamic connector shape or a custom shape. Since these shapes are fairly common, the method can return a known value for either case without loading the XML document and executing a query. Thus, if the shapeMaster variable contains the substring "connector", it returns a value of 0 to the calling code. If it contains the substring "sheet", the method returns a value of -1.

If the shapeMaster string does not fulfill either of the first two conditions, the method loads the ShapeConversion.xml document from the project resources. Note that the code uses the GetExecutingAssembly() method to get a reference to the assembly and then uses the GetManifestResourceStream(String) to get the XML document from the resources. This is necessary to ensure that the code can access the ShapeConversion.xml document after the add-in is built, distributed, and installed on other computers. The resulting stream is used to create an instance of the XDocument class in the xDoc variable by using the Load(Stream) method.

Next the LINQ to XML query is defined by using the members of the XDocument class. When executed, the query gets an IEnumerable collection of the Shape elements that are contained in the ShapeConversion.xml document, compares the value of the name attribute to the shapeMaster variable, and then selects the inner XML content (the value in the PPTShape elements) of any Shape element that meets the criteria. Note that the method also uses LINQ method syntax to set a default value of -1 for the query, using the DefaultIfEmpty<TSource>(IEnumerable<TSource>, TSource) method. After the query is executed, the shapeInt variable is set to the value of the first result that the query returns (or to the default value if no results were returned).

Note

For more information about how to construct LINQ to XML queries, see Basic Queries (LINQ to XML) and How to: Find an Element with a Specific Attribute.

In the ShapeConversion.vb or ShapeConversion.cs file, add the following code, which reads the ShapeConversion.xml file, looks for a string in the XML, and returns an integer value.

Private Function LookupVisioToPowerPoint() As Integer

    ' Use the shape's name to determine its corresponding master shape.
    Dim shapeNameArray() As String = shapeName.Split(".")
    Dim shapeMaster As String = shapeNameArray(0)

    ' Declare a variable for the result to return to the calling code.
    Dim shapeInt As Integer 

    ' Check whether the shape is a Dynamic connector 
    ' or a Sheet (which has no master shape).
    If (shapeMaster.ToLower.Contains("connector")) Then

        ' The shape is a Dynamic connector; return a value of 0.
        shapeInt = 0

    ElseIf (shapeMaster.ToLower.Contains("sheet")) Then

        ' The shape is a custom shape or guideline and has no equivalent.
        ' Return a value of -1.
        shapeInt = -1

    Else
        ' Query the XML data source for the shape.
        ' Load the XML file into memory.
        Dim assmbly As Assembly = Assembly.GetExecutingAssembly()
        Dim stream As Stream = assmbly.GetManifestResourceStream( _
            "ExportVisPPT.ShapeConversion.xml")
        Dim xDoc As XDocument = XDocument.Load(stream)

        ' Define the LINQ to XML query.
        Dim elements = _
            From el In xDoc.Descendants("Shape")
            Where (el.Attribute("name") = shapeMaster)
            Select el.Value

        ' Execute the query.
        shapeInt = elements.DefaultIfEmpty(-1).FirstOrDefault()

        ' Release the memory used for the xDoc object.
        xDoc = Nothing
    End If

    ' Return the value of shapeInt.
    Return shapeInt
End Function
private int LookupVisioToPowerPoint(){

    // Use the shape's name to determine its master shape.
    string[] shapeNameArray = shapeName.Split('.');
    string shapeMaster = shapeNameArray [0];

    // Set default value of shapeInt to -1, meaning there is no equivalent.
    int shapeInt;

    // Check whether the shape is a Dynamic connector 
    // or a Sheet (which has no master shape).
    if ((shapeMaster.ToLower().Contains("connector")))
    {
        // Return a value of 0, since the shape is a Dynamic connector.
        shapeInt = 0;
    }

    else if ((shapeMaster.ToLower().Contains("sheet")))
    {
        // Return a value of -1, as there is no PowerPoint equivalent.
        shapeInt = -1;
    }

    else
    {
        // Query the XML data source for the shape.
        // Load the XML file into memory.
        Assembly assmbly = Assembly.GetExecutingAssembly();
        Stream stream = expVisPPTAssembly.
            GetManifestResourceStream("ExportToPPT.ShapeConversion.xml");
        XDocument xDoc = XDocument.Load(stream);

        // Define the LINQ to XML query.
        var elements = 
            from el in xDoc.Descendants("Shape")
            where (el.Attribute("name") == shapeMaster)
            select el.Value

        ' Execute the query and set the shapeInt variable.
        shapeInt = elements.DefaultIfEmpty(-1).FirstOrDefault()

        // Release the memory from the xDoc object.
        xDoc = null;
    }

    // Return the shapeInt variable.
    return shapeInt;
}

Download the code