One of the most useful capabilities of Visio Professional and Visio Plan 2 is to link external data to shapes and have them refreshed by changes in the data source. So, many of my solutions involve writing code to make these links, and they are covered with some VBA examples in my book, Mastering Data Visualization with Microsoft Visio Professional 2016, but I mostly write C# code in VSTO add-ins, so I thought it would be useful to demonstrate how easy it is to create data links by dropping a shape, and by adding links to an existing shape. The book, by the way, is still relevant for the current Visio Professional and Visio Plan 2 editions!
I have uploaded a short video to YouTube to demonstrate and included the LinqPad code listings below.
DropLinkedPerson
This code uses the selected data recordset to drop a Person master shape in the centre of the page, linked to a specified person row.
void Main()
{
var vApp = MyExtensions.GetRunningVisio();
if (vApp.ActiveDocument == null) return;
if (vApp.ActivePage == null) return;
Visio.Window win = vApp.ActiveWindow;
Visio.Document doc = vApp.ActiveDocument;
Visio.Page pag = vApp.ActivePage;
int DiagramServices = doc.DiagramServicesEnabled;
doc.DiagramServicesEnabled = (int)Visio.VisDiagramServices.visServiceAll;
Visio.Window winDrs =
win.Windows.ItemFromID[(int)Visio.VisWinTypes.visWinIDExternalData];
if (winDrs.Visible)
{
Visio.DataRecordset drs = winDrs.SelectedDataRecordset;
if (drs != null)
{
var criteria = $"[Name] = 'Jim Kim'" ;
var mst = doc.Masters["Person"];
var x = 0.5 * pag.PageSheet.CellsU["PageWidth"].ResultIU;
var y = 0.5 * pag.PageSheet.CellsU["PageHeight"].ResultIU;
Array rowIDs = drs.GetDataRowIDs(criteria);
for (int i = 0; i < rowIDs.Length; i++)
{
var shp = pag.DropLinked(mst,x,y,
drs.ID,(int) rowIDs.GetValue(i),true);
}
}
}
doc.DiagramServicesEnabled = DiagramServices;
}
DropLinkedDepartmentPersonnel
This code uses the selected data recordset to drop Person master shapes for each person from a specified department.
void Main()
{
var vApp = MyExtensions.GetRunningVisio();
if (vApp.ActiveDocument == null) return;
if (vApp.ActivePage == null) return;
Visio.Window win = vApp.ActiveWindow;
Visio.Document doc = vApp.ActiveDocument;
Visio.Page pag = vApp.ActivePage;
int DiagramServices = doc.DiagramServicesEnabled;
doc.DiagramServicesEnabled = (int)Visio.VisDiagramServices.visServiceAll;
Visio.Window winDrs =
win.Windows.ItemFromID[(int)Visio.VisWinTypes.visWinIDExternalData];
if (winDrs.Visible)
{
Visio.DataRecordset drs = winDrs.SelectedDataRecordset;
if (drs != null)
{
var criteria = $"[Department] = 'Marketing'" ;
var mst = doc.Masters["Person"];
var x = 0.5 * pag.PageSheet.CellsU["PageWidth"].ResultIU;
var y = 0.5 * pag.PageSheet.CellsU["PageHeight"].ResultIU;
Array rowIDs = drs.GetDataRowIDs(criteria);
if (rowIDs.Length > 0)
{
var dY = y / rowIDs.Length;
var undoScope = vApp.BeginUndoScope("Dropping linked shapes");
for (int i = 0; i < rowIDs.Length; i++)
{
var shp = pag.DropLinked(mst, x, y + (i * dY),
drs.ID, (int)rowIDs.GetValue(i), true);
}
vApp.EndUndoScope(undoScope,true);
}
}
}
doc.DiagramServicesEnabled = DiagramServices;
}
DropLinkedPersonInRoom
This code uses the selected data recordset to add a data link to a simple shape with Office Number text which is used to get a person row.
void Main()
{
var vApp = MyExtensions.GetRunningVisio();
if (vApp.ActiveDocument == null) return;
if (vApp.ActivePage == null) return;
Visio.Window win = vApp.ActiveWindow;
Visio.Document doc = vApp.ActiveDocument;
Visio.Page pag = vApp.ActivePage;
if (win.Selection.Count == 0)
{
return;
}
var shp = win.Selection.PrimaryItem;
var shpText = shp.Characters.Text.ToString();
int.TryParse(shpText, out int off_nmbr);
if (off_nmbr == 0)
{
return;
}
int DiagramServices = doc.DiagramServicesEnabled;
doc.DiagramServicesEnabled = (int)Visio.VisDiagramServices.visServiceAll;
Visio.Window winDrs =
win.Windows.ItemFromID[(int)Visio.VisWinTypes.visWinIDExternalData];
if (winDrs.Visible)
{
Visio.DataRecordset drs = winDrs.SelectedDataRecordset;
if (drs != null)
{
var criteria = $"[Office_Number] = {off_nmbr}" ;
Array rowIDs = drs.GetDataRowIDs(criteria);
for (int i = 0; i < rowIDs.Length; i++)
{
shp.LinkToData(drs.ID, (int) rowIDs.GetValue(i),true);
}
}
}
doc.DiagramServicesEnabled = DiagramServices;
}
DropLinkedPersonnelInRooms
This code uses the selected data recordset to add a data link to selected simple shapes with Office Number text which is used to get a person row for each.
void Main()
{
var vApp = MyExtensions.GetRunningVisio();
if (vApp.ActiveDocument == null) return;
if (vApp.ActivePage == null) return;
Visio.Window win = vApp.ActiveWindow;
Visio.Document doc = vApp.ActiveDocument;
Visio.Page pag = vApp.ActivePage;
if (win.Selection.Count == 0)
{
return;
}
var sel = win.Selection;
int DiagramServices = doc.DiagramServicesEnabled;
doc.DiagramServicesEnabled = (int)Visio.VisDiagramServices.visServiceAll;
Visio.Window winDrs =
win.Windows.ItemFromID[(int)Visio.VisWinTypes.visWinIDExternalData];
if (winDrs.Visible)
{
Visio.DataRecordset drs = winDrs.SelectedDataRecordset;
if (drs != null)
{
var undoScope = vApp.BeginUndoScope("Adding data links to shapes");
foreach (Visio.Shape shp in sel)
{
var shpText = shp.Characters.Text.ToString();
int.TryParse(shpText, out int off_nmbr);
if (off_nmbr != 0)
{
var criteria = $"[Office_Number] = {off_nmbr}";
Array rowIDs = drs.GetDataRowIDs(criteria);
for (int i = 0; i < rowIDs.Length; i++)
{
shp.LinkToData(drs.ID, (int)rowIDs.GetValue(i), false);
}
}
}
vApp.EndUndoScope(undoScope, true);
}
}
doc.DiagramServicesEnabled = DiagramServices;
}
Note that I do not recommend using the ApplyDataGraphicsAfterLink = true argument for this particular code because Visio can take a while to insert DataGraphics into each shape, but the foreach loop does not wait for the previous shp to finish its update.
GetRunningVisio
This is the extension to get the running Visio application.
// MyExtensions
using System;
using System.Runtime.InteropServices;
using LINQPad;
using Microsoft.Office.Interop.Visio;
public static Application GetRunningVisio()
{
Application vApp = null;
try
{
vApp = (Application)Marshal.GetActiveObject("Visio.Application");
}
catch (Exception ex)
{
Extensions.Dump<string>("Couldn't find running Visio instance", ex.Message);
}
return vApp;
}
Related posts
Linking Data to Shapes in Visio after using Data Visualizer
Data Visualizer (DV) in Visio Plan 2 (Data | Create from Data | Create ) is great because it provides a way of automatically creating a diagram from data, but it also prevents some of the other data-linking features in Visio from being used. This is because DV wants to take control of the data…
Using Visio Color by Value on Connectors
Data Graphics in Visio Plan 2 and Visio Professional is great, but it only enables us to use them with 2D shapes in Visio, i.e. not on connectors. So, what if you want to change the line colour of the connectors between the 2D shapes because of the data flowing between them? Well, it is…
Understanding Visio Data Graphic’s Color by Value
The desktop Visio editions, Visio Professional and Visio Plan 2, have a great way of automatically displaying data as Data Bars, Icon Sets, Text Callouts and Color by Value. The first three types of Data Graphics require sub-shapes to be inserted into each shape that they are applied to, but the last one, Color by…
Pushing Data Visualizer in Visio to the limits!
Regular readers of my blog will know that I like to use the Data Visualizer (DV) in Visio Plan 2, but I recently tried to help a user who really decided to push it to the limits. In this scenario, there were multiple connections, but with different labels, being created between the same flowchart shapes,…
Update any Visio ShapeSheet cell with External Data
When Microsoft introduced a new way of linking external data to Visio shapes in 2007, I initially bemoaned the inability to update anything but Shape Data row values, unlike the old database add-on that I had been using for 10 years. The new method, though, has many advantages over the old way, not least that…
Keeping Visio Data Graphic Items Level
My good friend Scott Helmers, Visio author and trainer, of Harvard Computing Group , recently asked for some help in keeping data graphic items level when their target shape is rotated. Fortunately, I was able to assist, so I thought I would explain how this can be done, and also update my Icon Maker macro…