edit master shape(s) in stencil with c#

Started by bensch, February 16, 2023, 02:33:49 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

bensch

hi there,

i want to programatically change a stencil. (the master-shape inside).

i'm working with this tutorial:
https://learn.microsoft.com/en-us/office/client-developer/visio/how-to-manipulate-the-visio-file-format-programmatically

the stencil-file format .vssx is slightly different to the visio drawing format .vsdx and i'm not able to read the xml structure of my master-shape.


      // Open the Visio file in a Package object.
      using (Package visioPackageVSSX = OpenPackage("stencil_prg.vssx",
        Environment.SpecialFolder.Desktop))

      {

// Write the URI and content type of each package part to the console.
IteratePackageParts(visioPackageVSSX);


// Get a reference to the Visio Document part contained in the file package.
PackagePart documentPartVSSX = GetPackagePart(visioPackageVSSX,
"http://schemas.microsoft.com/visio/2010/relationships/document");

//---------------------------------------


// Get a reference to the collection of pages in the document,
// and then to the first page in the document.
PackagePart pagesPart = GetPackagePart(visioPackageVSSX, documentPartVSSX,
"http://schemas.microsoft.com/visio/2010/relationships/pages");

// no page part in stencil!
PackagePart pagePart = GetPackagePart(visioPackageVSSX, pagesPart,
"http://schemas.microsoft.com/visio/2010/relationships/page");

PackagePart mastersPart = GetPackagePart(visioPackageVSSX, documentPartVSSX,
"http://schemas.microsoft.com/visio/2010/relationships/masters");

PackagePart masterPart = GetPackagePart(visioPackageVSSX, mastersPart,
"http://schemas.microsoft.com/visio/2010/relationships/master");


//---------------------------------------

// Open the XML from the Masters Contents part.
XDocument mastersXML = GetXMLFromPart(masterPart);

//---------------------------------------


// Get all of the shapes from the page by getting
// all of the Shape elements from the pageXML document.
IEnumerable<XElement> shapesXML = GetXElementsByName(mastersXML, "Shape");
// Select a Shape element from the shapes on the page by
// its name. You can modify this code to select elements
// by other attributes and their values.
//XElement startEndShapeXML =
// GetXElementByAttribute(shapesXML, "NameU", "Masterr");
XElement startEndShapeXML =
GetXElementByAttribute(shapesXML, "Name", "Shape_A");

}



there is only one shape in the stencil which is called "shape_A".

i'd like to know how to change the last part of this code to get an object with my shapedata.

see the contents of \stencil_prg\visio\masters\masters.xml below.


<?xml version='1.0' encoding='utf-8' ?>
<Masters xmlns='http://schemas.microsoft.com/office/visio/2012/main' xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' xml:space='preserve'>
<Master ID='2' NameU='Masterr' IsCustomNameU='1' Name='shape_A' IsCustomName='1' Prompt='shape_A_prompt' IconSize='1' AlignName='2' MatchByName='1' IconUpdate='1' UniqueID='{00E2BBC3-0002-0000-8E40-00608CF305B2}' BaseID='{C7BEC382-EE1C-4857-A753-E0EA1FE5621B}' PatternFlags='0' Hidden='0' MasterType='2'>
<PageSheet LineStyle='0' FillStyle='0' TextStyle='0'>
<Cell N='PageWidth' V='0.7874015748031498'/>
<Cell N='PageHeight' V='0.7874015748031482'/>
<Cell N='ShdwOffsetX' V='0.1181102362204724'/>
<Cell N='ShdwOffsetY' V='-0.1181102362204724'/>
<Cell N='PageScale' V='0.03937007874015748' U='MM'/>
<Cell N='DrawingScale' V='0.03937007874015748' U='MM'/>
<Cell N='DrawingSizeType' V='4'/>
<Cell N='DrawingScaleType' V='0'/>
<Cell N='InhibitSnap' V='0'/>
<Cell N='PageLockReplace' V='0' U='BOOL'/>
<Cell N='PageLockDuplicate' V='0' U='BOOL'/>
<Cell N='UIVisibility' V='0'/>
<Cell N='ShdwType' V='0'/>
<Cell N='ShdwObliqueAngle' V='0'/>
<Cell N='ShdwScaleFactor' V='1'/>
<Cell N='DrawingResizeType' V='1'/>
</PageSheet>
<Icon>
AAABAAEAICAQFAAAAADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/w
D/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAB3d3d3d3d3d3d3d3d3dwAA//////////////////8
AAP//////////////////AAD//////////////////wAA//////////////////8AAP//////////
////////AAD//////////////////wAA//////////////////8AAP//////////////////AAD//
////////////////wAA//////////////////8AAP//////////////////AAD///////////////
///wAA////////j4j///////8AAP///////4d/////////AAD////////4j////////wAA///////
/94////////8AAP//////////////////AAD//////////////////wAA//////////////////8A
AP//////////////////AAD//////////////////wAA//////////////////8AAP///////////
///////AAD//////////////////wAA//////////////////8AAP//////////////////AAD///
///////////////wAA//////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAD/////gAAAAYAAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAA
A4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADg
AAAA4AAAAOAAAAB/////w==</Icon>
<Rel r:id='rId1'/>
</Master>
</Masters>



respectivly see the contents of \stencil_prg\visio\masters\master1.xml below.

<?xml version='1.0' encoding='utf-8' ?>
<MasterContents xmlns='http://schemas.microsoft.com/office/visio/2012/main' xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' xml:space='preserve'>
<Shapes>
<Shape ID='5' Type='Shape' LineStyle='3' FillStyle='3' TextStyle='3'>
<Cell N='PinX' V='0.393700787401575'/>
<Cell N='PinY' V='0.3937007874015741'/>
<Cell N='Width' V='0.7874015748031495'/>
<Cell N='Height' V='0.7874015748031482'/>
<Cell N='LocPinX' V='0.3937007874015748' F='Width*0.5'/>
<Cell N='LocPinY' V='0.3937007874015741' F='Height*0.5'/>
<Cell N='Angle' V='0'/>
<Cell N='FlipX' V='0'/>
<Cell N='FlipY' V='0'/>
<Cell N='ResizeMode' V='0'/>
<Section N='Geometry' IX='0'>
<Cell N='NoFill' V='0'/>
<Cell N='NoLine' V='0'/>
<Cell N='NoShow' V='0'/>
<Cell N='NoSnap' V='0'/>
<Cell N='NoQuickDrag' V='0'/>
<Row T='RelMoveTo' IX='1'>
<Cell N='X' V='0'/>
<Cell N='Y' V='0'/>
</Row>
<Row T='RelLineTo' IX='2'>
<Cell N='X' V='1'/>
<Cell N='Y' V='0'/>
</Row>
<Row T='RelLineTo' IX='3'>
<Cell N='X' V='1'/>
<Cell N='Y' V='1'/>
</Row>
<Row T='RelLineTo' IX='4'>
<Cell N='X' V='0'/>
<Cell N='Y' V='1'/>
</Row>
<Row T='RelLineTo' IX='5'>
<Cell N='X' V='0'/>
<Cell N='Y' V='0'/>
</Row>
</Section>
<Text>A
</Text>
</Shape>
</Shapes>
</MasterContents>

Visisthebest

Bensch that is an awfully complicated way to achieve this, from my perspective. You can do this from C# as well to simply change some masters in a stencil:
http://www.visguy.com/2008/02/25/edit-visio-masters-programmaticallythe-right-way/

Hope this helps.
Visio 2021 Professional

Nikolay

#2
@Visisthebest
You need to have Visio installed to be able to follow this article, though, and this code won't run on a server (i.e. unattended).

But yes, I agree, and I would probably also start with something like this only if I had a gun next to my head.

For other office applications, they wrote at least some helpers in OpenXml SDK like "WordprocessingDocument" and "Spreadsheet",
with Visio, unfortunately, you have to do it the hard way.

bensch

thanks to your replies, guys.

at least i'd like to get it working with that xml way.
shouldn't it be the same???

open the shape / master, edit and save back.

Nikolay

#4
It is not quite clear what you mean by saying you "i'm not able to read the xml structure of my master-shape" in the first message.
You showed it's xml right below, or? Do you get some error message, or what is the problem?

Other than that, searching github on "System.IO.Packaging" + "Visio" gives this for example (among other things):
https://github.com/hoveytechllc/visio-stencil-creator/blob/cb03f09fcc589989e607257848c485ee7a3fe089/VisioStencilCreator/VisioStencilFile.cs

Looks like something that could be useful to you?

bensch

thanks for the link!
--
let me tell you about my task

i have a stencil .vssx which shapes need some rework like setting connection points or guarding the aspect ratio and resize text related to the ratio ...
they are similar from the outline, but the content is different. so there is often a common base for all of them and a customa part.

my idea was to read out the existing xml, search for the corresponding tags and add or change them with c# (like the connection points which doesn't exist at all)


the next idea is to "draw" the shapes in xml to not need to draw them by hand in visio. i'd like to define the shape in text which can then be drawn by visio to graphics.
to have them in all discribed in a textual base seems to be nicer to work with instead of drawing lines by hand(mouse) :-)


i started be reading out the xml with the tutorial from ms because i couldnt find something else - and i dont want to buy this aspose framework. i want to do it on my own.

i can read out the xml parts, but at some point my stencil file differs from the visio drawing which ist used in the tutorial. so i needed to change the relationships to extract the correct shape data. for example a stencil has no page part, a drawing has. that's where the code from above is coming from.

the other idea of defining the shape in xml and let visio draw is at the actual state:
i found out that the visio 2003 .vsx format is xml with can be loaded directly and then be saved as a stencil.

the problem here is that the xml data i have is from the visio 2016 format and it's different to the "DataDiagramML" from microsoft for visio 2003.


so the correct subject for this post could be also like "creating (master-)shapes / stencil from xml"


i'm really thinking of getting an old version of visio now :-)

Yacine

#6
Quote from: bensch on February 22, 2023, 12:12:12 PM
... to have them in all discribed in a textual base seems to be nicer to work with instead of drawing lines by hand(mouse) :-)

What a statement.  :o ;D
Yacine

Visisthebest

#7
Bensch this is very doable with a tool (a .net library) where you read all the XML in to an object model, then change the object model, and serialize it back to XML.

It will probably require a deep dive in to how Visio structures its files and the library you use for reading and writing XML.

What hack might work:

1. Create the unchanged masters in a Visio file (file 1.)
2. Open file 1 and change the relevant masters with VBA and save as file 2.
3. Compare the XML in the file created by 1. and 2. and see where the changes are.
4. Write some code that surgically applies exactly these changes in the XML (read and write as a UTF8 text file).

It could be that this simple hack is also workable, depending on how complex the find/replace code to hack the XML is. Then you can just work directly on the XML as a text file.
Visio 2021 Professional

wapperdude

#8
Just so there are no assumptions, the stencil file (vssx) is a co!!section of 1 or more "master" shapes that are common!y, frequently used.  Typically they need none to minor alterations.  The working file (vsdx) is the canvass upon which the Visio drawing is made.  It can have 0 - any vssx files within it.  The vssx files are the resource from which the masters are drag and dropped onto the active drawing page.

So, now that that is out of the way, the questions that come to mind are:
1). How many "master" shapes need to be altered...A few, a lot?
2). How extensive are the changes?
        Just resizing, color changes?  Line styles? 
        Extensive?  Adding lines, changing shapes.
E).  Do you need to keep a copy of the original?

The method of editing a text file seems problematical, error prone, and even time consuming.  It even can lose many of the built-in tools that the visually oriented Visio product has to offer.  In the stated example, locking aspect ratio can be done directly from the ribbon with just a couple clicks.  Similarly, adding connection pts is just a matter of a few clicks from UI ribbon. Upfront, I don't know XML. but I'm failing to see how editing a text file has advantage.  It's slower and error prone (typos, etc).  Then you still have to flush it back into the master to verify you have what you wanted.  An in between method, to me, seems to be the shapesheet.  At least you can have 2 windows open ...the drawing page and shapesheet... and instantly see impact of changes. 

If there are many shapes that need altering then automating with code is a practical approach.

I may be missing something, but the whole Visio concept was to use visually oriented objects to quickly draw visual diagrams.
Visio 2019 Pro

Paul Herber

Just to clear up one small point (pedant? Moi? Oui!) open stencils within a document are only references. They are not included. The stencil reference will be a full path and a stencil name but if the stencil is later opened and the stencil is not available at the suggested path then Visio will attempt to find it among the stencil paths it knows about. Hence, if a doc is created using one version of Visio using the built-in shapes and a reference is created to, say, the Basic Shapes stencil then if the doc is then opened on a different computer with a different version of Visio then the paths to the built-in stencils is different.
You can't belive everything the XML tells you. ::)


Electronic and Electrical engineering, business and software stencils for Visio -

https://www.paulherber.co.uk/