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!
Chris says
Hi,
Nice site…
I m using com object to create org. chart and want to change color of different shape/node. How can i achieve it?
Thanks in advance
Visio Guy says
Hi Chris,
You can program Visio to change the color of a Visio shape by setting cell-formulas in the FillForegnd section of the ShapeSheet. Go to Window > Show ShapeSheet to see what I’m talking about.
Fill color cells are: FillForegnd and Fillbackgnd.
This code will change the fill of the first selected shape in a window to red:
ActiveWindow.Selection(1).Cells(“FillForegnd”).Formula = “rgb(255,0,0)”
That should get you started!
– Chris
Lisa Wenzel says
Hello Guy,
I’m looking for a way to find out the master of a selected shape and use this name to select the same shape on another page. how can I read the name of the Master (and the position of the selected shape) and use this to select the same shape on another page?
Perhaps you have an idea or can write an article about. I would like to move or delete a shape which is on all pages on the same position with one action.
best regards,
Lisa
Jacob says
Hello Visio Guy,
You have very good knowledge in Visio programming and i am sure you can help me with my problem. I am creating an orgchart using Visio.Application.ActivePage.Drop(vShape, dblXLocation, dblYLocation). The chart is fine but I wanted to “arrange subordinates” “side by side” “Double Side” programmatically. How can I do so?
If it’s not possible, is there a way of mentioning the default subordinate positioning type as “side by side” “Double Side”
Jacob
Visio Guy says
Hi Jacob,
What you want to do is possible, but it’s hard to describe in just a comment. I’ll try and give you some hints here.
You need to (programmatically) select the shape that is the parent of the children to be arranged, then call the appropriate OrgChart add-on commands.
For Visio 2007, the add-on is called “OrgC11”, but you have to know which arguments to pass to it. And the arguments have changed in the past and might change in the future, so you need to be sure which version of Visio is being used.
These are found by examining the Visio UIObject, looking at the actions for the buttons in the “Organization Chart” toolbar.
A few code examples would then be:
Call Visio.Application.Addons(“OrgC11”).Run(“/toolbar_horiz1”)
Call Visio.Application.Addons(“OrgC11”).Run(“/toolbar_sidebyside2”)
Again, that is with the superior shape selected. The arguments for Run() were found by digging through the document’s CustomToolBarSets to find the AddOnName and AddOnArgs for the Organization Chart toolbar. I don’t know if those arguments will work in Visio 2003, though.
Get the Visio 2007 SDK to find out more about analyzing the User Interface.
Alternatively, you can figure out which shapes are “child” shapes of a particular org-chart box, then do your own layout on them. To determine which shapes are connected to which shapes, you’ve got to do some work. Have a look at this thread in the Visio Guy forums to get started:
How to Identify the Shapes Connected by a Specific Connector
Jacob says
Hi Visio Guy,
Thank you very much for your help. It worked. I searched for this in Microsoft sites and in several other sites. But only your solution worked.
Based on your advice, I tried examining the Visio UIObject, looking at the actions for the buttons in the “Organization Chart” toolbar but could not figure out how to do it. Can you throw some lights on it? I could reach up to the UIObject in object browser.
I also need to insert picture to my orgchart shape. I went through your example. It works fine from Macro. I am using VB.NET 2005. How can I do it from VB.NET. The main problem I faced is there is no “sendkey”, the sendkeys.Send function does not accept argument false after the {Enter}.
Hope I did not confuse you.
Once again Thanks for the help
Jacob
Jacob says
Hi Visio Guy,
Do you have any suggestions for inserting picture into visio shape from vb.net
Jacob
Visio Guy says
Hi Jacob,
Shape objects have an Import method. Just call shp.Import(filepath)
Cheers,
Chris
Jacob says
Hi Chris,
Thankyou for the quick response. Shape.Import(filename) is importing the file to the page not into the shape. Am i doing something wrong
Jacob
Visio Guy says
If your shape is a group (ie: shp.Shapes.Count > 0) the image should be imported into the group.
Jacob says
You are right. It’s getting imported. How do I achieve the same behaviour of InsertPicture i.e. when I use shape.import(…), it does not resize the picture to the height of the shape nor it aligns the picture to the left of the shape. Please help.
This is one solution I found while searching for this. It works from VBA / Macro. But I am opening Visio from my VB.NET application and setting the OrgChart.
——————————————————————————————————————————-
Dim shp As Visio.Shape
Dim adn As Visio.Addon
Set adn = Visio.Addons(“OrgC11”)
‘Loop thru your shapes
Set shp = Visio.ActivePage.Shapes(“Assistant”)
Visio.ActiveWindow.DeselectAll
Visio.ActiveWindow.Select shp, Visio.VisSelectArgs.visSelect
SendKeys “C:\Users\davidp\Pictures\anypicture.jpg{ENTER}”, True
adn.Run “/cmd=InsertPicture”
‘end loop
——————————————————————————————————————————–
Also in your previous post you have mentioned about examining the Visio UI object. Do you use some tools for it? Can you share with me how to do it?
Jacob says
Hi Visio Guy,
Do you have any suggestions for me
Jacob
Sam says
How want to edit visio shape data programatically plz reply.
Lars-Erik Miedema says
Sam,
Maybe this will help.
Also have a look around the forum, there’s a topic about something that might come close here. Good luck
Anna says
Visio experts, please help!
I would like to create a macro to run the add-ons. Can someone please tell me how? Thanks!
Visio Guy says
Hi Anna,
The Visio.Application object has an add-ons collection. You can start there…
Also, for general questions, not related to the Visio Guy article, please try our forum: http://www.visguy.com/vgforum
Cheers,
Chris
Abdul Ghani says
Hi Visio Guyz,
I am working on a project where in I need to save the properties of master in to SQL DataBase, is there any way to accomplish this. I have done allot of googling for but did’nt any useful article hope you can help me.
Its Urgent..
Please reply
flow3rgirlz says
Hi,
i’m new with vba and macro. I tried to run your code but it requires me the insert macro. Can u please explain to me how to run the code. Thanks.
Visio Guy says
Hi F3,
Try this article: Just For Starters
flow3rgirlz says
Hi,
I draw a picture in visio. I would like to save the picture as master in stencil. Is there a way to create a new stencil and add the picture as master in it? I tried to google it and still couldnt find any way to do it. I also try to make a dummy stencil and try to edit it as what u shown above. But it still doesn’t work. Can anyone please help me out. I’m sort of stuck in here.
Thanks in advance…
Visio Guy says
Hi F3G,
This article is about programmatically editing masters.
To manually create a master, you just drag from the drawing to a stencil. It’s best to group whatever you draw first into a single shape first (Shape > Grouping > Group or Ctrl + G)
You can create a new stencil in which to create the master via:
File > Shapes > New Stencil
Or you can put the master in the “local” stencil of a document:
File > Shapes > Show Document Stencil
Stencils that open with Visio templates (as purchased from Microsoft) are non-editable. Stencils that you create open read-only when opened with a template. But you can click on the icon in the top-left corner of the stencil and choose “Edit Stencil” to make it writable.
flow3rgirlz says
Hi Visio Guy,
I would like to program it automatically using vba.
Robert says
Hi Visio Guy,
This is a great macro concept but there is one little bit still missing and I cant seem to figure it out. I have custom built shapes with some basic stencil icons. Well when I change the Masters at the shapesheet level, manually or programicly, my icon is reduced to a garbled mess.
How do I keep my icon from changing?
Visio Guy says
Hi Robert,
1. Right click a master
2. Choose Edit Master > Master Properties…
3. Un-check: Generate icon automatically from shape data
aannuu says
hi
I just want to create a visio application using .net with a textbox and a image insertion. Please anyone can help me.
Visio Guy says
Hi aannuu,
That’s a pretty small question that requires a really big answer!
You might try posting your question on our Visio Guy Forum and try to be a bit more specific as to what you need to do, and what you don’t understand.
Yousuf says
My question specially for Visio Guy (Chris Roth): how can you find the commands for Visio Add ons like OrgC11?
you mentioned:
Call Visio.Application.Addons(“OrgC11?).Run(“/toolbar_horiz1?)
Call Visio.Application.Addons(“OrgC11?).Run(“/toolbar_sidebyside2?)
How can we find information about other commands? Using Macro recoderder is no help!
Many thanks,
Yousuf.
gnash says
My question related to this function is about the assignment when the shape is grouped:
Set shp = mstCopy.Shapes(1)
This seems to point to the first the first shape in the grouped shape and not the containing “wrapper” shape.
My goal is to perform the following on a master shape in the stencil using the code in this article:
shp.CellsSRC(visSectionObject, visRowMisc, visHideText) = True
If I run this code against a shape object on the layout page created from a master, it is executed against a parent shape object that may or may not contain additional shapes ~ shape.shapes.count > 1 = true ~ the shape is grouped…
So inspecting the master of the shape I see the same internals, namely shape.shapes.count > 1 = true. The assumption with the above is that the first shape is assumed to point to the container shape or a grouped object? I would expect based on the shape object model something like this to be the suggested approach.
Set shp = mstCopy.Shapes(1).RootShape
For a grouped shape on the layout page RootShape points to the desired containing shape, however for a master shape RootShape = nothing.
What is the suggested approach to reference the RootShape of a master shape?
Visio Guy says
Hi gnash,
Shapes have a shp.ContainingPage, shp.ContainingMaster or shp.ContainingShape (sub-shapes of groups). I would have preferred .ContainingPage to work for both pages and masters, but oh well.
But you don’t have to go that far. Once you have a master, you can get it’s PageSheet, ie: mstCopy.PageSheet. This is a ShapeSheet, essentially the same as a page, but with slight variation in cell names.
If you want to hide text on a shape, you don’t want the “master wrapper”, you really want the shape. So you should do something like this:
In your code you were doing:
shp.CellsSRC(visSectionObject, visRowMisc, visHideText) = true
but you should do something more like:
shp.CellsSRC(visSectionObject, visRowMisc, visHideText).ResultIU = 1
as the code snippet above shows.
Christian Lindenau says
I wrote a Module to copy the insert Picture function from the Visio Organigramm addon.
Feel free to use it.
Christian Lindenau says
Sorry for exploding the commentbox :/
VG: no worries, I cleaned it up a bit!
Jay says
Hi VisioGuy,
I’m trying to save instances from one master stencil as new masters (otherwise create my own stencil and copy a stencil from another file into my custom stencil). So far I’ve managed to create the stencil and create an empty master, but I can’t seem to find a way to copy the master over … even with (Set mstCopy = mst.Open). Any ideas?
Thanks!
J
Btw the master I’m trying to copy contains a few user defined cells which I’d like to capture as well.
Jay says
I think I may have had the wrong approach to my problem. After going back to the design board I think I’ve found a suitable workaround which simply requires adding images as fill patterns. Does anyone know how this is done though C#?
Thanks,
-J
Josh309 says
super helpful. this site is better than online microsoft help..
Milan says
Hi Visio,
PLEASE REPLY ASAP. My deadline is approaching
I am trying to auto fit my text in shape cells. I found out in visio we have to provide GUARD(MAX(TEXTWIDTH(TheText), 1 in)) in width and
GUARD(MAX(TEXTHEIGHT(TheText,Width), 0.75 in)) in hieght .
But how to achieve this in vb.net
I tried below code but it threw a compiler error.
vToShape.Cells(“Width”).Formula =(MAX(TEXTWIDTH(TheText),0.75 in))
ChrisB says
Hi Visio Guy,
Firstly, this is a top rate site – thanks for your time and effort in pulling this information together.
Secondly, I do have a question relating to Shape Masters – of course!
I have written a visio app to document a technical data solution in terms of relationships between tables and SQL scripts (table x read by script 1 and writen to table y which is read by script 2 and written to table z wich is read….. – you get the picture?)
When you drop a script object on the screen (a process shape) it identifies if there is a corresponding page in the document of that same name – i.e. ‘Script 2’ – if so, it changes to that page – if not it creates a new page (called Script 2) and drops a ‘code_block_desc’ shape onto the page (having set pagination, scaling etc., so it fills the page).
The code_block_desc object is a shape master that I have built myself – in truth a collection of other shapes arranged in a way to represent a form where key data is captured.
This shape master is made up of lots of individual shapes – and these are NOT grouped prior to being saved as the Shape Master.
One of the first elements (sub-shapes) in the master is a placeholder for the script name – however, I can’t seem to find a way to select the element (which is not a sub-shape as it’s not a group) to automatically set the script name value.
I’m trying to set up other automation tasks (hyperlinks to script files based upon text values stored in other elements) but all are dependent upon me extracting text from various elements.
I’m happy to send a copy of the shape master if you’re happy to send me an email address – any help you can offer will be greatly appreciated.
Regards,
(Another) Chris
ChrisB says
I’ve answered my own question – I put some nominal text into each sub-shape/element that would uniquely identify it, and then ran this simple code block:
This returned the following:
Giving me a working map of each component part of my master shape, meaning I can now identify, access or set the value of any cell in my master shape programatically.
If there’s a way to re-order the index of each element so no1 starts top left, and 60 is bottom right, then that would be even more helpful – but not crucial.
Thanks again…
ChrisB says
D’oh!
Opened the shae Master to edit it, and looked at the Drawing Explorer Window – used this to navigate around each component piece of the master and renamed ‘process.17’ to ‘Script_Name’, etc., etc.
Now I can call upon the value or set the value of every single component by name or ID.
now gives me:
My solution is now really taking shape.
Visio Guy says
Hi Chris,
You can name the subshapes within a shape. Even better, these shapes are protected in scope from other shapes on a page, so you can have ten shapes with sub-shapes named “Script”.
These subshapes won’t get the auto-indexed names that you may have run into: Script.1, Script.2, Script.3, etc.). Because they are ‘protected’ within the group. Top-level shapes on a page or within a group (ie: ‘in the same scope’) can’t have the same name, and will get the suffix-indexing, just for your information.
So if you’re using Visio 2010, go to the Developer tab and click Shape Name. There you can rename a selected shape or subshape within a group. Now you can easily find a subshape by name.
Or you can iterate:
Rajashekar says
How to hide a shape from visio programatically using C#??
Visio Guy says
Hi Rajashekar,
There are many ways to hide shapes. You’ll want to read this article first: The Hidden World of Visio Shapes.
So, the first example in the article would look something like this in C#:
Rajashekar says
shp.Cells[“Geometry1.NoShow”].ResultIU = 1;
shp.Cells[“Geometry2.NoShow”].ResultIU = 1;
shp.Cells[“Geometry3.NoShow”].ResultIU = 1;
shp.CellsU[“HideText”].ResultIU = 1;
i guess the above code is not working in visio 2003.
can u sugesst any othr method.
Visio Guy says
That is example code. Your shape might not have all three Geometry sections.
Rajashekar says
Can u suggest a method in which multiple shapes are put in a box?
Visio Guy says
Hi Rajashekar,
Your question is too general and would take hours and hours to answer. Plus, it doesn’t really relate to this article.
Cheers,
Chris
Rajashekar says
hi…
If a shape contains multiple sheets in Visio,then how can we add text to different sheet programmatically using C#? can anyone help me in this
Visio Guy says
Shapes have shapes collections if they are groups.
Gediminas says
Hello,
I am just trying to get into Visio shapesheet and basics of VBA this function you posted would suit me perfect, but I my basic knowledge of VBA is not enough. I can’t find a way to modify your function so it would work in my drawing. Maybe you could add extra annotations, where I should enter master name and how I should do that. I mean either i should use something like Set mst = Visio.ActiveDocument.Masters.Item(“MasterName”) or other expresion
Rob says
Hi VG,
Bit late to the party with this but how could I save the stencil programatically after I’d edited the masters this way?
Cheers,
Rob