Enhancing the Built-In Containers in #Visio

The concept of Structured Diagrams was introduced in Visio 2010 to provide core functionality for a variety of the templates in Visio, such as the Cross-Functional Flowchart, BPMN Diagram and Wireframe Diagram. This is primarily evident as Containers, Lists and Callouts and they can be customized (see Custom Containers, List and Callouts ), as shown in some of my previous articles ( see https://blog.bvisual.net/?s=container). One example of this extension can be found in all of the flowchart shapes that placed into a swimlane in a cross-functional flowchart. They have a Shape Data row, Function, that automatically inherits the text entered into the header of the swimlane. In another example, a Visio user can use Insert / Diagram Parts / Container to visually group other shapes together, and update the header text of the container. Well, I often do want my custom shapes to inherit the text of a container, so, in this article, I show how the built-in containers can be enhanced to provide this ability.

InheritingContainerText

You should be aware that I often exploit the fact that Visio creates a local copy of each master shape that it uses within a document. This can be modified and set to match master by name on drop, to ensure that it is the one to use, even if the original Microsoft provided version is used. In this case, I use this trick to create hidden, enhanced versions of the containers that are available in the gallery of containers. Microsoft also do this with the Dynamic connector shape in a number of their own templates.

If you examine the Function Shape Data row of any of the flowchart shapes, then you will find the formula:

=IFERROR(CONTAINERSHEETREF(1,"Swimlane")!User.VISHEADINGTEXT,"")

This formula will get the value of the User.visHeadingText cell in the first container, that it is within, with the category “Swimlane“.

This is possible because there is a User-defined Cell row, with the reserved name msvShapeCategories, in the Swimlane shape. This cell can store a semi-colon separated list of categories. In fact, the formula for the User.msvShapeCategories cell in the Swimlane shapes is:

="Swimlane;DoNotContain"

This means that it belongs to two categories, Swimlane and DoNotContain.

The reason why the Function Shape Data row references the User.visHeadingText cell is because the Swimlane is a group shape, and the text is actually in one if the sub-shapes, with the value in User.msvStructureType = “Heading”. Therefore, the reference is to another cell, User.visHeadingText that gets the text of a sub-shape with the following formula (where n is the ID of the sub-shape):

=SHAPETEXT(Sheet.n!TheText)

This means that the formula in any other shape just needs to get a reference to the known User.visHeadingText cell. Well, all of the built-in containers are a very similar structure to the Swimlane shape, but the User.visHeadingText cell is not always present. Therefore, my bit of VBA code below simply enhances any containers with a Heading sub-shape, so that the User.visHeadingText cell is present, and it returns the text that it finds.

It is not essential that the containers are filtered by a category, so the following formula is also valid, and would return the value in the first container, if it has a User.visHeadingText cell (casing is not important):

=IFERROR(CONTAINERSHEETREF(1)!User.VISHEADINGTEXT,"")

 

Now, all of the containers in the ribbon have the following formula in the User.msvShapeCategories cell:

="ContainerStyleDefaults"

This can be edited to store any other custom category too. So the following formula would make the container have two categories, either of which could be used as a filter:

="ContainerStyleDefaults;My Container"

It is easy to add all of the built-in containers quickly because the ribbon gallery will replace the currently selected container shape with the gallery item. The container masters will be added to the document stencil, as in the following example.

InsertingAllContainers

Then the EnhanceContainers macro will update all of these copies in the document stencil, and hide them from the normal stencil view too.

RunEnhanceContainerMacro

All that remains is to prepare the Shape Data row of any master that needs to inherit the value of the container text with the following formula:

=IFERROR(CONTAINERSHEETREF(1,"My Container")!User.VISHEADINGTEXT,"")

For example, I added the above formula into the Owner Shape Data row in the Process master shape.

AddingContainerSheetFormula

 

The VBA Code

Insert one or more containers from Insert / Diagram Parts / Container into your document, delete them (not using Undo), then run the following macro. It will enhance them all.

Public Sub EnhanceContainers()
'Author : David Parker, Jul 2018, No rights reserved
'Purpose: To enhance any container masters in the active document
' to regularise the reference to the heading text
'Usage : Add the following ShapeSheet function to Shape Data rows
' =IFERROR(CONTAINERSHEETREF(1,opt_category)!User.VISHEADINGTEXT,"")
' where opt_category is an optional category,
' listed in the User.msvShapeCategories cell of the container
On Error GoTo errHandler
Dim mst As Visio.Master
Dim mstEdit As Visio.Master
Dim shp As Visio.Shape
Dim subShp As Visio.Shape
Dim strType As String
Dim strSubType As String
Dim headingSheet As String
Dim categories As String
Dim aryCats() As String
Dim newCategories As String
Dim i As Integer
Dim catExists As Boolean

Const ROWTYPE As String = "User.msvStructureType"
Const CELHDR As String = "visHeadingText"
Const ROWCAT As String = "User.msvShapeCategories"
Const CONTAINERCAT As String = "My Container"   'Optional category
Const UDCSECT As Integer = Visio.VisSectionIndices.visSectionUser
Const FLGEX As Integer = Visio.VisExistsFlags.visExistsAnywhere

For Each mst In ActiveDocument.Masters
  If mst.Shapes(1).CellExists(ROWTYPE, FLGEX) <> 0 Then
    headingSheet = ""
    strType = mst.Shapes(1).Cells(ROWTYPE).ResultStr("")

    If strType = "Container" Then
      'Open the master to edit it
      Set mstEdit = mst.Open
      Set shp = mstEdit.Shapes(1)
      For Each subShp In shp.Shapes
        If subShp.CellExists(ROWTYPE, FLGEX) <> 0 Then
          strSubType = subShp.Cells(ROWTYPE).ResultStr("")
          If strSubType = "Heading" Then
            'Get the NameID of the Heading sub-shape
            headingSheet = subShp.nameId
            Exit For
          End If
        End If
      Next subShp

      'If necessary, update the container categories
      categories = shp.Cells(ROWCAT).ResultStr("")
      If Len(CONTAINERCAT) > 0 Then
        If Len(categories) > 0 Then
          aryCats = Split(categories, ";")
          For i = 0 To UBound(aryCats)
            If aryCats(i) = CONTAINERCAT Then
              catExists = True
              Exit For
            End If
          Next I
          If catExists = False Then
            newCategories = categories & ";" & CONTAINERCAT
          End If
        Else
          newCategories = CONTAINERCAT
        End If
      End If
      shp.Cells(ROWCAT).FormulaForceU = "=""" & newCategories & """"

      If Len(headingSheet) > 0 Then
        'Create the visHeadingText cell
        If shp.CellExists("User." & CELHDR, FLGEX) = 0 Then
          shp.AddNamedRow UDCSECT, CELHDR, 0
        End If
        'Set the fomula for the visHeadingText cell
        shp.Cells("User." & CELHDR).FormulaForceU = _
          "=SHAPETEXT(" & headingSheet & "!TheText)"
        End If
        'Close the master edit object
        mstEdit.Close
        mst.matchByName = True
        mst.Hidden = 1
      End If
    End If
Next mst

exitHere:
  Exit Sub
errHandler:
  MsgBox Err.description, vbExclamation, "EnhanceContainers"
  Resume exitHere
End Sub

 

BTW, I always put this sort of code in a macro-enabled stencil that I sve into the My Shapes folder.

Caution! Do not specify “Swimlane” as a category for your containers because the Microsoft BASFLO add-on behaves badly, and won’t let you edit the text in the header!

A macro-enabled stencil with the above code can be downloaded from here

An enhanced sample diagram can be downloaded here

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Simplify Tasks

Want to learn the simple way?

Paul Turley's SQL Server BI Blog

sharing my experiences with the Microsoft data platform, SQL Server BI, Data Modeling, SSAS Design, Power Pivot, Power BI, SSRS Advanced Design, Power BI, Dashboards & Visualization since 2009

John Goldsmith's visLog

be smart, be clear, be visual ...

Mo's blog

Personal views on Dynamics 365 for Operations and Technical Architecture.

Chris Webb's BI Blog

Microsoft Power BI, Analysis Services, MDX, DAX, M, Power Pivot and Power Query

davecra.wordpress.com/

Microsoft Office 365 Development, and more...

PowerShell.Amsterdam

Automate, Accelerate, Accurate

johnvisiomvp

Life with Visio and other Microsoft Toys!

Title (Required)

Windows Server Essentials Tips & Tricks

Nilsandrey's Weblog

Just another WordPress.com weblog

Things that Should be Easy

Every so often (too often in the IT industry) I encounter things that should have been very easy to do but turned out to be far too complicated. My favorite topics include SharePoint, .Net development, and software architecture, especially distributed systems.

Visio Guy

Smart graphics for visual people

Pluralsight blog

be smart, be clear, be visual ...

%d bloggers like this: