Site icon bVisual

Understanding Visio Connections

A reader recently asked if I could explain how to programmatically get the shapes connected to a shape in Visio. So, I thought I would have a go, because there are alternatives, depending upon which functions are used, and what parameters are passed to them. The following animated gif is rotating around the different types of selections that can be made from the lower Decision shape. Normally, two 2D shapes are connected together using a 1D shape. The 1D shape has a direction because it starts from “BeginX” and finishes at “EndX”. This is irrespective of an arrowheads that the user may have chosen to adorn the 1D connector with at either end.

The above image shows my multiSelect tool in use, which is available free from http://bvisual.net/Products/multiSelect.aspx.

The following image shows the same diagram, but with the ID of each shape shown. The Decision shape with an ID=65 is selected. It has one inward connector, labelled Maybe, and two outwards connectors labelled No and Yes.

 

So, the request is how to get the connected shapes … Well, the connectors are glued to the Decision shape, and the opposite end of each connector is glued to another shape.

Originally, Visio developers had to follow the Connects and FromConnects collection of the Shape object, and the direction of the 1D connector shapes can be derived from knowing if the connected cell is named BeginX or EndX.

Then Microsoft introduced a GluedShapes(…) method and a ConnectedShapes(…) method which return an array of shape IDs, and have arguments to filter the direction and category of the target shapes.

 

GetGluedShapes

The following C# code (written in LinqPad) gets the glued outgoing 1D shapes and selects them (in addition to the originally shape(s)  – the Decision shape).

var vApp = MyExtensions.GetRunningVisio();

Visio.Window win = vApp.ActiveWindow;

Visio.Selection sel = vApp.ActivePage.CreateSelection(Visio.VisSelectionTypes.visSelTypeEmpty);
foreach (Visio.Shape shp in win.Selection)
{
    sel.Select(shp, (short) Visio.VisSelectArgs.visSelect);    //If source shape still required
    GetGlued(shp,Visio.VisGluedShapesFlags.visGluedShapesOutgoing1D, “”, sel, true);
}

vApp.ActiveWindow.Selection = sel;

 

 

It also outputs the following rows:

Decision.65 is glued to

Dynamic connector.70

Decision.65 is glued to

Dynamic connector.71

The GetGlued(…) function

void GetGlued(Visio.Shape shp,
    Visio.VisGluedShapesFlags whichGluedShapes, string category,
    Visio.Selection selection, bool addToSelection)
{
    Array aryTargetIDs;
    aryTargetIDs = shp.GluedShapes(whichGluedShapes, category);
    for (int i = aryTargetIDs.GetLowerBound(0); i <= aryTargetIDs.GetUpperBound(0); i++)
    {
        Visio.Shape gluedShape = shp.ContainingPage.Shapes.ItemFromID[(int) aryTargetIDs.GetValue(i)];
        //LinqPad only –
        gluedShape.Name.Dump(shp.Name + ” is glued to”);
        if (addToSelection)
        {
            selection.Select(gluedShape, (short)Visio.VisSelectArgs.visSelect);
        }
    }
}

 

ConnectedShapes

The following C# code (written in LinqPad) gets the connected outgoing 2D shapes and selects them (in addition to the originally shape(s)  – the Decision shape).

var vApp = MyExtensions.GetRunningVisio();

Visio.Window win = vApp.ActiveWindow;

Visio.Selection sel = vApp.ActivePage.CreateSelection(Visio.VisSelectionTypes.visSelTypeEmpty);
foreach (Visio.Shape shp in win.Selection)
{
    sel.Select(shp, (short) Visio.VisSelectArgs.visSelect);    //If source shape still required
    GetConnected(shp, Visio.VisConnectedShapesFlags.visConnectedShapesOutgoingNodes, “”,sel, true);
}

vApp.ActiveWindow.Selection = sel;

It also outputs the following rows:

Decision.65 is connected to

Process.54

Decision.65 is connected to

Process.67

The GetConnected(…) function

void GetConnected(Visio.Shape shp,
    Visio.VisConnectedShapesFlags whichConnectedShapes, string category,
    Visio.Selection selection, bool addToSelection)
{
    Array aryTargetIDs;
    aryTargetIDs = shp.ConnectedShapes(whichConnectedShapes, category);
    for (int i = aryTargetIDs.GetLowerBound(0); i <= aryTargetIDs.GetUpperBound(0); i++)
    {
        Visio.Shape connectedShape = shp.ContainingPage.Shapes.ItemFromID[(int)aryTargetIDs.GetValue(i)];
        //LinqPad only –
 &
#160;      connectedShape.Name.Dump(shp.Name + ” is connected to”);
        if (addToSelection)
        {
            selection.Select(connectedShape, (short) Visio.VisSelectArgs.visSelect);
        }
    }
}

 

GetShapeConnects

The following C# code (written in LinqPad) gets the connected outgoing 1D and 2D shapes and selects them (in addition to the originally shape(s)  – the Decision shape).

var vApp = MyExtensions.GetRunningVisio();
if (vApp.ActiveWindow == null) return;
Visio.Window win = vApp.ActiveWindow;

Visio.Selection sel = vApp.ActivePage.CreateSelection(Visio.VisSelectionTypes.visSelTypeEmpty);
foreach (Visio.Shape shp in win.Selection)
{
    sel.Select(shp, (short) Visio.VisSelectArgs.visSelect);    //If source shape still required
    GetShapeConnects(shp, true ,sel, true, true);
}

vApp.ActiveWindow.Selection = sel;

It also outputs the following rows:

Shape

65 : Decision.65

FromConnect

65 : Decision.65 – 101 – Connections.X2 < 71 : Dynamic connector.71 – 9 – BeginX

Shape

71 : Dynamic connector.71

Connect

71 : Dynamic connector.71 – 12 – EndX > 54 : Process.54 – 3 – PinX

FromConnect

65 : Decision.65 – 103 – Connections.X4 < 70 : Dynamic connector.70 – 9 – BeginX

Shape

70 : Dynamic connector.70

Connect

70 : Dynamic connector.70 – 12 – EndX > 67 : Process.67 – 3 – PinX

 

The GetShapeConnects(…) function calls itself, traversing the 1D connectors

void GetShapeConnects(Visio.Shape shp, bool? outwardOnly,
    Visio.Selection selection, bool add1DToSelection, bool add2DToSelection)
{
    //LinqPad only –
    (shp.ID.ToString() + ” : ” + shp.Name).Dump(“Shape”);

    //Used when the incoming shape is 1D
    foreach (Visio.Connect cnxn in shp.Connects)
    {
        if ((!outwardOnly.HasValue) ||
            outwardOnly.HasValue && outwardOnly.Value.Equals(true) && cnxn.FromCell.Name.Equals(“EndX”) ||
            outwardOnly.HasValue && outwardOnly.Value.Equals(false) && cnxn.FromCell.Name.Equals(“BeginX”))
        {
            //LinqPad only –
            (cnxn.FromSheet.ID + ” : ” + cnxn.FromSheet.Name + ” – ” + cnxn.FromPart.ToString() + ” – ” + cnxn.FromCell.Name +
            ” > ” + cnxn.ToSheet.ID + ” : ” + cnxn.ToSheet.Name + ” – ” + cnxn.ToPart.ToString() + ” – ” + cnxn.ToCell.Name)
            .Dump(“Connect”);

            if (add2DToSelection)
            {
                selection.Select(cnxn.ToSheet, (short) Visio.VisSelectArgs.visSelect);
            }
        }
    }
    //Used when the incoming shape is 2D
    foreach (Visio.Connect cnxn in shp.FromConnects)
    {
        if ( (!outwardOnly.HasValue) ||
            outwardOnly.HasValue && outwardOnly.Value.Equals(true) && cnxn.FromCell.Name.Equals(“BeginX”) ||
            outwardOnly.HasValue && outwardOnly.Value.Equals(false) && cnxn.FromCell.Name.Equals(“EndX”))
        {
            //LinqPad only –
            (cnxn.ToSheet.ID + ” : ” + cnxn.ToSheet.Name + ” – ” + cnxn.ToPart.ToString() + ” – ” +    cnxn.ToCell.Name +
            ” < ” + cnxn.FromSheet.ID + ” : ” + cnxn.FromSheet.Name + ” – ” + cnxn.FromPart.ToString() + ” – ” + cnxn.FromCell.Name)
            .Dump(“FromConnect”);

            if (cnxn.FromCell.Name.Equals(“BeginX”))
            {
                GetShapeConnects(cnxn.FromSheet, true, selection, add1DToSelection, add2DToSelection);
            }
            else if (cnxn.FromCell.Name.Equals(“EndX”))
            {
                GetShapeConnects(cnxn.FromSheet, false, selection, add1DToSelection, add2DToSelection);
            }
            if (add1DToSelection)
            {
                selection.Select(cnxn.FromSheet, (short)Visio.VisSelectArgs.visSelect);
            }
        }
&
#160;   }
}

 

NB. All of the Connect objects are actually stored in the Page.Connects collection, so this could be used as an alternative. The Visio type library re-purposes them as Connects and FromConnects collections on each shape. If you examine the native vsdx XML, you will only find Page.Connects elements.

Exit mobile version