If you are busy developing a Visio solution, you might run into the situation where you need to edit a Visio master using code.
Like any application that has survived the ages, Visio has its share of black-magic techniques that lurk in dusky corners of the netherworld. And if you need to edit masters programmatically, be warned! You’re heading down a dark alley…
If you’ve already run into problems with this, don’t feel bad. Even experienced Visio developers get tripped-up by this one! And that’s because the correct way to do this isn’t obvious, and the obvious way to do it isn’t correct!
The Obvious Way Doesn’t Work…Kind-of
When you peruse the Visio object model, you’re likely to think that the obvious way to edit a master shape is something like this:
Dim mstCopy As Visio.Master
Dim shp As Visio.Shape
'// Get a master named "Bob" from our Document stencil:
Set mst = Visio.ActiveDocument.Masters.Item("Bob")
'// Get the shape inside of the master:
Set shp = mst.Shapes.Item(1)
But what happens when you run this code? Your masters change, but those changes don’t seem to percolate down to shapes on the page!
If you are programmatically altering the masters in the Document Stencil of a Visio drawing, then the instances of those masters (ie: the shapes dropped on the page) won’t reflect your changes!
However, if you save your drawing, close it, then re-open, you’ll see that your changes did indeed take effect. Yes something is happening, but not in an ideal way.
Create a Master Editing Session…duh!
Now, we don’t want to edit masters, then programmatically close and open the drawing. That just wouldn’t do! So…
The proper way to get the job done is to start an editing session. The situation is very similar to what you do when you edit a master by hand:
- Open a master window (double-click a master, or right-click and choose Edit Master > Edit Master Shape)
This creates a temporary copy of the master - Make your changes manually: format, resize, edit text, etc.
- Close the master window
- Accept your changes by responding Yes to the prompt: Update master and all of its instances?
Step 4 is the key for manual editing. You consciously must push the changes to the instances.
This is missing from our code above. It never tells Visio to push the changes to the instances in the drawing. For that matter, that simple code never really creates a copy to fiddle with in the first place!
And that’s because the right way is all very, very non-obvious!
So we mimic the manual sitaution by using the Master.Open method to create a copy of our original master, then we push the changes to the drawing by calling Master.Close. The sample code below says it all:
Sub EditMaster( ByRef mst As Vis.Master )
Dim mstCopy As Visio.Master ' an object to hold a copy of mst...
Dim shp As Visio.Shape
Set mstCopy = mst.Open
Set shp = mstCopy.Shapes(1)
'// Do stuff to shp here...
shp.Text = "Example stuff"
Set shp = Nothing
mstCopy.Close()
Set mstCopy = Nothing
Set mst = Nothing
End Sub
The code above works for VB6 and VBA. Dot-netters can just remove all of the Set statements, and probably don’t really need the = Nothing stuff either, since .NET is supposed to handle clean-up all by itself.
So make use of those Master.Copy and Master.Close methods to create a master editing session. Your on-the-fly programmatic changes to Visio masters will then work just fine, and you’ll be a hero at that next status meeting!
Visio Guy says
Hi Rob,
Stencils are Visio documents just like any other drawing. Visio document objects have these methods:
Save
SaveAs
SaveAsEx
When you’re editing stencils that are docked, it might be slightly more tricky to figure out which stencil is which document. But each stencil that is opened in the stencil pane is still part of the Visio.Application.Documents collection.
Reto Zingg says
Great article.
Question: how do you close a master that was left open? During development of my code I have times where the program exits due to an error and leaves the master open (as it never reaches the master.Close). Next time I run the code Visio complains that the master is already opened for editing… what is the easiest way to closing the master, ideally in the GUI?
Thanks!
Visio Guy says
Hi Reto,
I don’t have time right now to research, but the way I remember it, is that a master that didn’t get properly closed would exist as a “name-dot” master, hidden in the stencil. So master “Car” would be “Car.6”, but you wouldn’t see it in the stencil. I *thought* that these magically got cleaned up on save or on open. But I can’t remember for sure.
Can you run Master.Close() if it’s detected as still open? Can you check the Master.Stat property before you hit an error? I’m not sure how to do this properly off the top of my head.
Another tack might be to try-catch your editing session and try your best to avoid the errors in the first place, so that you can always close the master regardless of what happens. There’s probably an option to throw away changes on close if you’re not happy (not sure on this either…)
Chris
Reto Zingg says
Hello Chris,
thanks much for your reply. I’ll dig into that a bit more. I’ll likely implement the try-catch.
An other issue I ran into: how do you do the “Edit Stencil” programmatically? I want to edit a master in a docked stencil. In the GUI I can right-click the stencil header and “Edit Stencil”, after which my script runs just fine. But I could not find out how to do that programmatically. Any clues?
Thanks!