In the previous post we looked at the Characters object in Visio and used it to find the runs of formatted text in a shape. In this post we’ll complete the scenario by reading the formatting information from the Shapesheet to match it up with the text runs. Here is our sample shape text with mixed formatting.
We walked through the function getTextRunList to generate a list of the substrings within shape text. Each string represents a text run - a set of characters that have the same formatting applied. So what are the formatting properties for each text run? This information is stored in the Character section of the Shapesheet.
Each row in the Character section corresponds to a text run. We can read the Shapesheet cells in these rows and associate the properties with the substrings in the text run list. Before looking at the code to do this, we need to create a simple structure to store the text and formatting information.
public string text;
public int font;
public double size;
public string color;
public bool bold, italic, underline;
This structure holds the text for the text run as well as six properties for the formatting. There are many more properties that describe Visio text, but these are the most common. Now let’s look at a function to extract the formatted text from a shape and generate a set of VisioFormattedTextRun objects. Note that you will need the getTextRunList procedure from the previous post.
using IVisio = Microsoft.Office.Interop.Visio;
public class TextUtilities
public static List<VisioFormattedTextRun> getFormattedShapeText(IVisio.Shape vsoShape)
List<VisioFormattedTextRun> formattedShapeText = new List<VisioFormattedTextRun>();
short charSection = (short)IVisio.VisSectionIndices.visSectionCharacter;
if (vsoShape.get_CellsU("HideText").ResultIU == 0)
// Break up the shape's text into a set of text runs
List<string> textRunList = getTextRunList(vsoShape);
// Iterate through the rows in the Characters section to get the formatting matching each text run
for (short iRow = 0; iRow < vsoShape.get_RowCount(charSection); iRow++)
VisioFormattedTextRun textRun = new VisioFormattedTextRun();
// Get the text for this row
textRun.text = textRunList[iRow];
// Make sure text is not empty before adding run
if (textRun.text.Length > 0)
// Get formatting for this text run
textRun.color = vsoShape.get_CellsSRC(charSection, iRow, (short)IVisio.VisCellIndices.visCharacterColor).get_ResultStrU(IVisio.VisUnitCodes.visNoCast);
textRun.font = (int)vsoShape.get_CellsSRC(charSection, iRow, (short)IVisio.VisCellIndices.visCharacterFont).ResultIU;
textRun.size = vsoShape.get_CellsSRC(charSection, iRow, (short)IVisio.VisCellIndices.visCharacterSize).get_Result((short)IVisio.VisUnitCodes.visPoints);
int styleProp = (int)vsoShape.get_CellsSRC(charSection, iRow, (short)IVisio.VisCellIndices.visCharacterStyle).ResultIU;
textRun.bold = ((styleProp & 1) == 1);
textRun.italic = ((styleProp & 2) == 2);
textRun.underline = ((styleProp & 4) == 4);
// Record text run
Let’s walk through this procedure. First an empty list of VisioFormattedTextRun objects is created. Then we check the HideText cell to find out if the shape text is actually being displayed. This sample only retrieves the text if HideText is 0 (i.e. text is visible). Next is the call to getTextRunList to create a list of text substrings with common formatting.
The main part of the routine iterates through all the rows in the shape’s Character section. A new VisioFormattedTextRun object is created. The text property is set to the current substring in the text run list. Then individual Shapesheet cells are read from the current row in the Character section. The six formatting properties are assigned, and the VisioFormattedTextRun object is added to the overall formatted shape text list.