OfficeIMO.Visio
1.0.2
Prefix Reserved
See the version list below for details.
dotnet add package OfficeIMO.Visio --version 1.0.2
NuGet\Install-Package OfficeIMO.Visio -Version 1.0.2
<PackageReference Include="OfficeIMO.Visio" Version="1.0.2" />
<PackageVersion Include="OfficeIMO.Visio" Version="1.0.2" />
<PackageReference Include="OfficeIMO.Visio" />
paket add OfficeIMO.Visio --version 1.0.2
#r "nuget: OfficeIMO.Visio, 1.0.2"
#:package OfficeIMO.Visio@1.0.2
#addin nuget:?package=OfficeIMO.Visio&version=1.0.2
#tool nuget:?package=OfficeIMO.Visio&version=1.0.2
OfficeIMO.Visio — .NET Visio Utilities
OfficeIMO.Visio provides helpers for creating and editing .vsdx drawings with Open XML.
- Targets: netstandard2.0, net472 (Windows), net8.0, net10.0
- License: MIT
- NuGet:
OfficeIMO.Visio - Dependencies: OfficeIMO.Drawing, System.IO.Packaging, Microsoft.Bcl.AsyncInterfaces (net472)
Install
dotnet add package OfficeIMO.Visio
Quick sample (fluent)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Fluent;
var vsd = VisioDocument.Create("diagram.vsdx");
vsd.AsFluent()
.Info(i => i.Title("Demo").Author("You"))
.Page("Page-1", p => p
.Title("Demo Flow")
.Rect("start", 1, 1, 2, 1, "Start")
.Diamond("decision", 4, 1.5, 2, 2, "Decision")
.Ellipse("end", 7, 1.5, 2, 1, "End")
.Connect("start", "decision", VisioSide.Right, VisioSide.Left,
c => c.RightAngle().ArrowEnd(EndArrow.Triangle))
.Connect("decision", "end", VisioSide.Right, VisioSide.Left,
c => c.RightAngle().ArrowEnd(EndArrow.Triangle).Label("Yes")))
.End();
vsd.Save();
Quick sample (editing an existing diagram)
using System;
using OfficeIMO.Visio;
using OfficeIMO.Visio.Fluent;
using OfficeIMO.Visio.Stencils;
using Color = OfficeIMO.Drawing.OfficeColor;
VisioDocument.Load("operations.vsdx")
.AsFluent()
.ExistingPage("Operations", page => page
.ShapesWithData("Owner", "Ops", selection => selection
.Fill(Color.LightBlue)
.ShapeData("Reviewed", "Yes", "Reviewed", VisioShapeDataType.Boolean))
.ShapesContainingText("Legacy", selection => selection
.Text(shape => shape.Text!.Replace("Legacy", "Production", StringComparison.Ordinal)))
.Rect("monitoring", 7, 4, 1.4, 0.8, "Monitoring")
.Connect("api", "monitoring", VisioSide.Right, VisioSide.Left, connector => connector
.RightAngle()
.ArrowEnd(EndArrow.Triangle)
.Label("metrics"))
.Connectors(selection => selection.LineColor(Color.DarkBlue)))
.End()
.Save("operations.updated.vsdx");
For create-or-edit workflows, use PageOrAdd(...) to configure an existing
page when it is present or create it with the same fluent page API when it is
missing. The fluent selection helpers reuse the typed selection model, so bulk
style, Shape Data, layer, hyperlink, and geometry edits stay AOT-friendly and
do not require dynamic dispatch or reflection.
Loaded-page fluent editing also supports higher-level diagram queries by shape id: contained/intersecting geometry, connected components, shortest paths, and incoming/outgoing/attached connector selections. That keeps common load-edit-save workflows readable even when the update is based on topology or layout rather than a single known shape id.
Native container membership can be maintained the same way. OfficeIMO updates
the typed member/owner graph and writes fresh Visio DEPENDSON(...)
relationships on save, so loaded containers can be refit without hand-editing
ShapeSheet formulas:
VisioDocument.Load("workflow.vsdx")
.AsFluent()
.ExistingPage("Workflow", page => page
.Rect("cache", 6, 4, 1.3, 0.7, "Cache")
.AddToContainer("runtime-tier", new[] { "cache" }, options => {
options.Margin = 0.35;
options.HeadingHeight = 0.3;
})
.RemoveFromContainer("runtime-tier", new[] { "legacy-db" })
.RelayoutContainerMembers("runtime-tier", layout => {
layout.Columns = 1;
layout.VerticalSpacing = 0.25;
})
.ConfigureContainer("runtime-tier", options => {
options.Margin = 0.4;
options.HeadingHeight = 0.3;
options.NoRibbon = true;
options.ShapeStyle = VisioStyleTheme.Technical().Container;
}, refit: true)
.RefitContainer("runtime-tier"))
.End()
.Save("workflow.updated.vsdx");
ContainerInfo(...) returns a typed snapshot of native container membership,
margin, heading height, auto-resize/lock flags, Visio style identifiers, and
current visual style. ConfigureContainer(...), ApplyContainerOptions(...),
and StyleContainer(...) update loaded containers by id and write the native
container User cells back into the VSDX package. OfficeIMO stores heading height
as an OfficeIMO User cell alongside Visio's native margin cell, so metric-page
containers can be refit after load without shrinking margins through unit
conversion drift.
Native Visio comments are also available as typed page state. OfficeIMO writes
the real /visio/comments.xml part, so comments survive normal Visio editing
instead of being modeled as decorative shapes:
VisioDocument.Load("workflow.vsdx")
.AsFluent()
.ExistingPage("Workflow", page => page
.CommentShape("review", "Confirm approval owner", "Operations", "OP")
.UpdateComment(1, "Approval owner confirmed", DateTimeOffset.UtcNow)
.ResolveComment(1, DateTimeOffset.UtcNow)
.Comment("Reviewed before release", "Operations", "OP"))
.End()
.Save("workflow.commented.vsdx");
Existing shapes can be standardized to generated or package-backed stencils from the same fluent loaded-page chain. Replacement preserves placement, text, style, layers, Shape Data, User cells, hyperlinks, and connector endpoints:
VisioDocument.Load("workflow.vsdx")
.AsFluent()
.ExistingPage("Workflow", page => page
.ReplaceMaster("review", VisioStencils.Flowchart.Get("decision"), resizeToMaster: true)
.ReplaceMastersByMaster("Process", VisioStencils.Flowchart.Get("preparation"), resizeToMaster: true))
.End()
.Save("workflow.standardized.vsdx");
For larger cleanup passes, a typed migration map lets you standardize whole
families of loaded shapes by current stencil id, master name, shape NameU, or
a strongly typed predicate. Rules are evaluated in order, so specific exceptions
can sit above broader migrations. Replacement stencils can be supplied directly
or resolved from a first-party or package-backed catalog by query:
VisioStencilMigrationMap migration = VisioStencilMigrationMap.Create(map => map
.MapStencilId("flow.process", VisioStencils.Infrastructure, new[] { "host", "server" }, resizeToStencil: true)
.MapMaster("Data", VisioStencils.DataPlatform, "relational", resizeToStencil: true)
.MapNameU("LegacyServer", VisioStencils.Network, "server", resizeToStencil: true));
VisioDocument.Load("legacy-workflow.vsdx")
.AsFluent()
.ExistingPage("Workflow", page => page.ApplyStencilMigration(migration))
.End()
.Save("workflow.migrated.vsdx");
When you need an approval step before changing a large diagram, plan the same map first. Planning is non-mutating and produces a stable text report for PRs, CI logs, or operator review. Save the report as an artifact when approval happens in another process, then load the approved plan and apply it with the map when you want OfficeIMO to verify that pages, shapes, match rules, and replacement stencils still match the report before mutating the loaded diagram:
VisioDocument legacy = VisioDocument.Load("legacy-workflow.vsdx");
VisioStencilMigrationPlan plan = legacy.PlanStencilMigration(migration);
Console.WriteLine(plan.ToText());
plan.SaveText("legacy-workflow.migration-plan.txt");
if (plan.HasChanges) {
VisioStencilMigrationPlan approved =
VisioStencilMigrationPlan.LoadText("legacy-workflow.migration-plan.txt");
legacy.ApplyStencilMigration(approved, migration);
legacy.Save("legacy-workflow.migrated.vsdx");
}
For common cleanup of unstenciled/basic flowchart-like diagrams, use the conservative preset. It upgrades shapes such as Rectangle, Diamond, Parallelogram, Hexagon, and Ellipse to semantically matching catalog stencils, while leaving shapes that already carry OfficeIMO stencil metadata alone:
VisioDocument legacyFlow = VisioDocument.Load("legacy-flow.vsdx");
VisioStencilMigrationResult result = legacyFlow.ApplyStencilMigration(
VisioStencilMigrationPresets.BasicFlowchart(VisioStencils.Flowchart));
legacyFlow.Save("legacy-flow.stenciled.vsdx");
Console.WriteLine($"Migrated {result.Count} shapes.");
The same preset model covers labeled network/infrastructure, architecture, swimlane/process-map, cloud infrastructure, security/identity, Kubernetes/container, data/platform, collaboration/business-process, org-chart, timeline, and sequence cleanup. These presets read common shape text/name cues such as server, database, firewall, switch, gateway, queue, region, storage, lane, phase, serverless function, identity provider, conditional access, container image, data lake, event stream, approval, business application, executive, milestone, release, participant, activation, and fragment, resolve the best matching stencil in the chosen catalog, and still skip shapes already tagged with OfficeIMO stencil metadata:
VisioDocument network = VisioDocument.Load("legacy-network.vsdx");
VisioStencilMigrationPlan networkPlan = network.PlanStencilMigration(
VisioStencilMigrationPresets.NetworkInfrastructure(VisioStencils.Network));
Console.WriteLine(networkPlan.ToText());
network.ApplyStencilMigration(
networkPlan,
VisioStencilMigrationPresets.NetworkInfrastructure(VisioStencils.Network));
network.Save("legacy-network.stenciled.vsdx");
VisioDocument architecture = VisioDocument.Load("legacy-architecture.vsdx");
architecture.ApplyStencilMigration(
VisioStencilMigrationPresets.ArchitectureInfrastructure(VisioStencils.Architecture));
architecture.Save("legacy-architecture.stenciled.vsdx");
VisioDocument roadmap = VisioDocument.Load("legacy-roadmap.vsdx");
roadmap.ApplyStencilMigration(
VisioStencilMigrationPresets.Timeline(VisioStencils.Timeline));
roadmap.Save("legacy-roadmap.stenciled.vsdx");
VisioDocument cloud = VisioDocument.Load("legacy-cloud.vsdx");
cloud.ApplyStencilMigration(
VisioStencilMigrationPresets.CloudInfrastructure(VisioStencils.Cloud));
cloud.Save("legacy-cloud.stenciled.vsdx");
VisioDocument security = VisioDocument.Load("legacy-security.vsdx");
security.ApplyStencilMigration(
VisioStencilMigrationPresets.SecurityIdentity(VisioStencils.SecurityIdentity));
security.Save("legacy-security.stenciled.vsdx");
VisioDocument platform = VisioDocument.Load("legacy-platform.vsdx");
platform.ApplyStencilMigration(
VisioStencilMigrationPresets.ContainersKubernetes(VisioStencils.ContainersKubernetes));
platform.ApplyStencilMigration(
VisioStencilMigrationPresets.DataPlatform(VisioStencils.DataPlatform));
platform.ApplyStencilMigration(
VisioStencilMigrationPresets.CollaborationBusiness(VisioStencils.CollaborationBusiness));
platform.Save("legacy-platform.stenciled.vsdx");
Quick sample (diagram builder)
using System;
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("flowchart.vsdx")
.Flowchart("Property buying Flowchart", flow => flow
.Title()
.Layout(VisioFlowchartLayout.TwoColumnContinuation)
.RouteBranches(laneSpacing: 0.5)
.Start("start", "Start with an agent\nyou trust")
.Step("consult", "Consult with agent to\ndetermine your property\nwants and needs")
.Step("market", "With agent, analyze\nmarket to choose\nproperties of interest")
.OffPage("jump", "A")
.Continue("resume", "A")
.Step("offer", "Select ideal property\nand write offer to\npurchase")
.Decision("agreement", "Negotiate\n& Counteroffer:\nAgreement?")
.Step("contract", "Accept the contract")
.End("close", "Close on the\nproperty")
.Branch("agreement", "No", "market")
.Callout("agreement", "retry-note", "Loop back if the offer is rejected", VisioSide.Right))
.Save();
The diagram builder creates normal Visio pages, semantic flowchart shapes, masters, side-glued connectors, labels, deterministic layouts, and routed branch/loop connectors. Flowcharts can also add semantic callouts with leader connectors for complex branches or reviewer notes, either by exact coordinates or by placing notes beside a target node. It is the first high-level authoring layer above the lower-level page/shape APIs.
Quick sample (block diagram builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("block-diagram.vsdx")
.BlockDiagram("Block Diagram", diagram => diagram
.Title()
.Legend()
.Region("processor", "Processor", 1, 2, 2, 2)
.Block("input", "Input Device", 0, 2)
.EmphasisBlock("memory", "Memory Unit", 1, 2)
.Block("storage", "Secondary\nStorage", 1, 0, VisioBlockShapeKind.Data)
.Block("control", "Control Unit", 1, 3)
.Block("alu", "Arithmetic &\nLogic Unit", 1, 4)
.Block("output", "Output Device", 3, 2)
.DataFlow("input", "memory")
.DataFlow("memory", "output")
.ControlFlow("control", "output", "Control Flow")
.Callout("memory", "memory-note", "Central shared state", VisioSide.Top))
.Save();
The block diagram builder creates grid-positioned blocks, light background regions, solid data-flow connectors, dashed control-flow connectors, labels, optional presentation titles/legends, semantic callouts, and master-backed Visio shapes. Callouts can be placed by coordinates or relative to a block side.
Quick sample (dependency diagram builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("dependencies.vsdx")
.DependencyDiagram("Service Dependencies", diagram => diagram
.Title()
.Theme(VisioStyleTheme.Fluent())
.External("users", "Users")
.Component("web", "Web App")
.Component("api", "API")
.Decision("policy", "Policy")
.Data("database", "Database")
.DependsOn("users", "web", "HTTPS")
.DependsOn("web", "api")
.ControlDependency("api", "policy", "Authorize")
.DataDependency("api", "database", "SQL")
.Callout("policy", "policy-note", "Authorization gates access to data", VisioSide.Top))
.EnsureVisualQuality(new VisioDiagramQualityOptions {
CheckConnectorShapeIntersections = false,
CheckConnectorLabelShapeOverlaps = false
})
.Save();
The dependency diagram builder creates deterministic layered DAG layouts from nodes and directed relationships. It automatically grows the page, places component/data/external/decision nodes, routes dependencies, supports semantic coordinate or side-placed callouts, and rejects cycles.
Quick sample (graph diagram builder)
using System;
using System.IO;
using System.Linq;
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
using OfficeIMO.Visio.Stencils;
using Color = OfficeIMO.Drawing.OfficeColor;
var installed = VisioStencilPackageCatalog.DiscoverInstalledVisioPackages()
.Where(path => Path.GetFileName(path).StartsWith("AZURE", StringComparison.OrdinalIgnoreCase));
var stencils = VisioStencilPackageCatalog.LoadMany(installed,
new VisioStencilPackageLoadOptions {
IncludeUnsupportedMasters = true
});
VisioDocument.Create("graph.vsdx")
.GraphDiagram("Event-driven graph", graph => graph
.Title()
.Layout(VisioGraphLayout.Layered)
.Direction(VisioGraphDirection.LeftToRight)
.StencilNode("gateway", "API", stencils.Search("API Management").First())
.StencilNode("events", "Events", stencils.Search("Event Grid").First())
.Node("worker", "Worker")
.Node("database", "Database", VisioGraphNodeKind.Data)
.NodeShapeData("gateway", "Owner", "Platform", "Owner",
VisioShapeDataType.String, "Owning support team")
.NodeHyperlink("gateway",
"https://learn.microsoft.com/azure/api-management/", "API docs")
.NodeShapeData("database", "Classification", "Confidential",
"Data classification", VisioShapeDataType.String)
.NodeStyle("worker", style => {
style.FillColor = Color.FromRgb(73, 80, 87);
style.LineColor = Color.FromRgb(45, 52, 59);
})
.Zone("runtime", "Runtime", "gateway", "events", "worker")
.Root("gateway")
.ControlEdge("gateway-publishes-events", "gateway", "events", "publish")
.EdgeShapeData("gateway-publishes-events", "Protocol", "HTTPS",
"Protocol", VisioShapeDataType.String)
.EdgeHyperlink("gateway-publishes-events",
"https://learn.microsoft.com/azure/event-grid/", "Event docs")
.Edge("events", "worker", "trigger")
.DataEdge("worker-writes-database", "worker", "database", "write")
.EdgeShapeData("worker-writes-database", "Port", "1433",
"Port", VisioShapeDataType.Number)
.EdgeHyperlink("worker-writes-database",
"https://example.org/contracts/write-model", "Write contract")
.EdgeStyle("worker-writes-database", style => {
style.LineColor = Color.FromRgb(0, 102, 204);
style.LineWeight = 0.026D;
})
.DataEdge("database", "gateway", "read model"))
.Save();
The generic graph builder is for real node/edge maps that are not strict DAGs
or one diagram domain. It supports layered, grid, and radial layouts; directed
and undirected edges; cycles; disconnected components; background zones; native
nodes; and source-aware VisioStencilShape nodes loaded from installed Visio
or external .vssx/.vstx packages. Use NodeShapeData and NodeHyperlink
to keep generated graph nodes searchable, inspectable, and linked to runbooks,
dashboards, API docs, or data catalogs inside Visio. Named edges can also carry
connector Shape Data with EdgeShapeData and hyperlinks with EdgeHyperlink,
which is useful for protocols, ports, trust levels, API contracts, message
schemas, queries, and relationship-specific runbooks. Use NodeStyle and
EdgeStyle for local visual emphasis without cloning or forking a whole theme.
For data-driven diagrams, import simple node and edge records. Missing edge IDs are derived from endpoint IDs and connector kind, so regenerated diagrams keep diff-friendly connector identity:
var idp = new VisioGraphNodeRecord("idp", "Entra ID") {
StencilCatalog = VisioStencils.SecurityIdentity,
IsRoot = true
};
idp.StencilQueries.Add("idp");
idp.ShapeData.Add("Owner", "IAM");
var cluster = new VisioGraphNodeRecord("cluster", "AKS Cluster") {
StencilCatalog = VisioStencils.ContainersKubernetes
};
cluster.StencilQueries.Add("kubernetes");
var flow = new VisioGraphEdgeRecord("idp", "cluster") {
Kind = VisioGraphConnectorKind.Control,
Label = "tokens"
};
flow.ShapeData.Add("Protocol", "OIDC");
var runtime = new VisioGraphClusterRecord("runtime", "Runtime", new[] { "cluster" });
runtime.ShapeData.Add("Owner", "Platform");
runtime.HyperlinkAddress = "https://example.org/runtime-runbook";
VisioDocument.Create("inventory-graph.vsdx")
.GraphDiagram("Imported Inventory", graph => graph
.Legend()
.Import(new[] { idp, cluster }, new[] { flow }, new[] { runtime })
.Cluster("identity", "Identity", "idp", "cluster")
.ZoneShapeData("identity", "Owner", "IAM"))
.Save();
Use Legend() on generic graph diagrams when the generated page should explain
which node kinds and connector kinds are present. The legend is derived from the
actual graph, reserves header space during layout, and is marked as generated
diagram adornment so polish and quality passes do not treat it as business
content.
Quick sample (architecture diagram builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("architecture.vsdx")
.ArchitectureDiagram("Jenkins on Azure", diagram => diagram
.Title()
.Legend()
.Theme(VisioStyleTheme.Technical())
.Region("vnet", "Virtual Network", 1, 0, 4, 3)
.Region("subnet", "Build Subnet", 1, 1, 4, 2)
.Actor("users", "Users", 0, 1)
.Gateway("public-ip", "Public IP", 1, 1)
.Service("jenkins", "Jenkins Server", 2, 1)
.Compute("agent", "Build Agent", 3, 1)
.Database("data", "Data", 2, 2)
.Storage("artifacts", "Artifacts", 4, 2)
.Security("vault", "Key Vault", 2, 0)
.DataFlow("users", "public-ip", "HTTPS")
.DataFlow("public-ip", "jenkins", "route")
.ControlFlow("jenkins", "agent", "scale")
.Dependency("jenkins", "vault", "secrets")
.Callout("jenkins", "scale-note", "Scale agents on demand", VisioSide.Right))
.Save();
The architecture builder creates dependency-free cloud/infrastructure diagrams
with semantic components, background regions, routed data/control/dependency
connectors, labels, coordinate or side-placed callouts, and the reusable
Technical theme.
Quick sample (network diagram builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("network.vsdx")
.NetworkDiagram("Branch Network", network => network
.Title()
.Theme(VisioStyleTheme.Technical())
.Zone("perimeter", "Perimeter", 0, 0, 3, 1)
.Zone("servers", "Server Zone", 3, 0, 3, 1)
.Zone("clients", "Client LAN", 1, 2, 5, 1)
.Internet("internet", "Internet", 0, 0)
.Firewall("firewall", "Firewall", 1, 0)
.Switch("core", "Core Switch", 2, 0)
.Server("app", "App Server", 3, 0)
.Database("db", "Database", 4, 0)
.Workstation("pc1", "Finance PC", 1, 2)
.Workstation("pc2", "Support PC", 2, 2)
.Printer("printer", "Printer", 3, 2)
.Ethernet("internet", "firewall", "WAN")
.Trunk("firewall", "core", "uplink")
.Trunk("core", "app", "10Gb")
.Ethernet("app", "db")
.Ethernet("core", "pc2")
.Ethernet("pc2", "printer")
.Callout("firewall", "edge-note", "Inspect and log inbound traffic", VisioSide.Top))
.Save();
The network builder creates dependency-free network maps with zones, typed devices, routed Ethernet/trunk/wireless/management links, coordinate or side-placed semantic callouts, and optional legends.
Quick sample (network topology diagram builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("network-topology.vsdx")
.NetworkTopologyDiagram("Branch Topology", topology => topology
.Title()
.Root("internet", "Internet", VisioNetworkNodeKind.Internet)
.Firewall("firewall", "Firewall")
.Switch("core", "Core Switch")
.Server("app", "App Server")
.Database("db", "Database")
.Workstation("finance", "Finance PC")
.Workstation("support", "Support PC")
.Printer("printer", "Printer")
.Subnet("edge", "Edge", "internet", "firewall", "core")
.Subnet("servers", "Server Zone", "app", "db")
.Subnet("clients", "Client LAN", "finance", "support", "printer")
.Ethernet("internet", "firewall", "WAN")
.Trunk("firewall", "core", "uplink")
.Trunk("core", "app", "10Gb")
.Ethernet("app", "db")
.Ethernet("core", "finance")
.Ethernet("core", "support")
.Ethernet("support", "printer")
.Callout("firewall", "edge-note", "North-south inspection point", VisioSide.Top))
.Save();
The topology builder is the graph-first network API: users describe devices and links, then OfficeIMO derives deterministic layers, grows the page when needed, adds subnet/background zones around selected devices, routes links, supports coordinate or side-placed semantic callouts, and keeps mesh/cycle links valid.
Quick sample (sequence diagram builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("sequence.vsdx")
.SequenceDiagram("Checkout Sequence", sequence => sequence
.Title()
.Theme(VisioStyleTheme.Fluent())
.Actor("customer", "Customer")
.Participant("web", "Web App")
.Control("api", "Orders API")
.Database("db", "Orders DB")
.Call("customer", "web", "Checkout")
.Call("web", "api", "POST /orders")
.Async("api", "db", "Persist order")
.Return("api", "web", "201 Created")
.SelfMessage("web", "Render receipt"))
.Save();
The sequence builder creates editable participants, lifelines, synchronous, asynchronous, return, and self-message connectors from semantic calls. It grows the page as needed, uses reusable style themes, and adds a native searchable sequence stencil catalog without depending on Visio templates at runtime.
Quick sample (swimlane diagram builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("swimlane.vsdx")
.SwimlaneDiagram("Order Fulfillment", swim => swim
.Title()
.Theme(VisioStyleTheme.Modern())
.Lane("customer", "Customer")
.Lane("sales", "Sales")
.Lane("ops", "Operations")
.Phase("request", "Request")
.Phase("review", "Review")
.Phase("approval", "Approval")
.Phase("fulfill", "Fulfill")
.Start("start", "Submit order", "customer", "request")
.Step("qualify", "Qualify order", "sales", "review")
.Decision("approved", "Approved?", "sales", "approval")
.Step("revise", "Revise request", "customer", "approval")
.Step("pick", "Pick items", "ops", "approval")
.Data("invoice", "Create invoice", "sales", "fulfill")
.End("ship", "Ship order", "ops", "fulfill")
.Flow("start", "qualify", "handoff")
.Flow("qualify", "approved")
.Exception("approved", "revise", "no")
.Handoff("approved", "pick", "yes")
.Flow("pick", "invoice")
.Flow("invoice", "ship")
.Callout("approved", "approval-note", "Escalate exceptions before fulfillment", VisioSide.Right))
.Save();
The swimlane builder creates editable role lanes, phase headers, semantic activities, labeled flows, dashed exception paths, deterministic routing, and automatic stacking when more than one activity lands in the same lane/phase cell. It supports coordinate or side-placed semantic callouts for risk and exception notes, and does not require Visio templates at runtime.
Loaded swimlane diagrams can be maintained with typed lane/phase/activity discovery and fluent moves:
using OfficeIMO.Visio;
using OfficeIMO.Visio.Fluent;
VisioDocument.Load("swimlane.vsdx")
.AsFluent()
.ExistingPage("Order Fulfillment", page => page
.MoveSwimlaneActivity("pick", "sales", "review", options => {
options.ActivityGap = 0.18;
options.AvoidShapes = false;
}))
.End()
.Save("swimlane-updated.vsdx");
Quick sample (org chart builder)
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("org-chart.vsdx")
.OrgChartDiagram("Leadership", org => org
.Title()
.Theme(VisioStyleTheme.Modern())
.Root("ceo", "Marta Nowak", "Chief Executive Officer")
.Assistant("ea", "Eli Green", "Executive Assistant", "ceo")
.Manager("cto", "Alex Chen", "Chief Technology Officer", "ceo")
.Manager("coo", "Sam Rivera", "Chief Operating Officer", "ceo")
.Manager("cfo", "Priya Shah", "Chief Financial Officer", "ceo")
.TeamBand("engineering", "Engineering", "cto")
.TeamBand("operations", "Operations", "coo")
.Position("platform", "Nina Patel", "Platform Lead", "cto", "engineering")
.Position("security", "Owen Brooks", "Security Lead", "cto", "engineering")
.Vacancy("sre", "Open SRE Role", "coo", "operations")
.External("advisor", "Taylor Reed", "Advisor", "cfo")
.Callout("cto", "cto-note", "Owns platform and security roadmap", VisioSide.Right))
.Save();
The org chart builder creates editable hierarchy cards, assistant placements, team bands, vacancies, external roles, routed reporting lines, and coordinate or side-placed semantic callouts from business relationships.
Reusable style themes
VisioStyleTheme gives diagrams and later editing passes a shared set of
shape, connector, and readable text styles. The built-in presets are Modern,
Office, Fluent, Technical, Enterprise, Cloud, Process, Minimal,
Dark, DarkSafe, and Print. PremiumPresets() returns the professional
set used for market-facing diagrams: enterprise, technical, cloud, process,
print-safe, and dark-safe.
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
var process = VisioStyleTheme.Process();
var darkSafe = VisioStyleTheme.DarkSafe();
var premiumThemes = VisioStyleTheme.PremiumPresets();
var doc = VisioDocument.Create("styled.vsdx")
.Flowchart("Styled Approval Flow", flow => flow
.Theme(process)
.Start("start", "Request received")
.Step("review", "Review request")
.Decision("approved", "Approved?")
.End("done", "Done"));
var page = doc.Pages[0];
page.SelectByMaster("Decision").Style(process.Decision);
page.SelectConnectedConnectors(page.FindShapeById("approved")!)
.Style(process.ControlConnector);
page.FitToContent(0.6, 0.45);
doc.Save();
VisioDocument.Create("dark-styled.vsdx")
.BlockDiagram("Dark-Safe System Blocks", diagram => diagram
.Theme(darkSafe)
.Region("zone", "Processing Zone", 0, 0, 3, 1)
.Block("input", "Input", 0, 0)
.EmphasisBlock("processor", "Processor", 1, 0)
.Block("output", "Output", 2, 0)
.DataFlow("input", "processor")
.ControlFlow("processor", "output", "control"))
.Save();
Connector routing
Connectors can stay dynamic for Visio-managed rerouting, or they can be pinned
to deterministic OfficeIMO-generated orthogonal routes and explicit waypoints.
This is useful for readable flowcharts, architecture diagrams, and edited
documents where a few important lines must avoid crossing the main content.
OfficeIMO-authored explicit waypoint routes also load back into the connector
model, so routed diagrams can be edited and saved again without losing the
route semantics.
Connectors can also be routed around unrelated top-level shapes with
RouteOrthogonalAroundShapes, or page-wide with
RouteConnectorsOrthogonalAroundShapes, when a generated path would otherwise
cut through important content. The typed VisioConnectorRoutingOptions overloads
can also treat containers, background surfaces such as zones or trust
boundaries, and generated adornments as obstacles when those surfaces should
visibly reserve routing space. Containers and background surfaces that contain
the connector source or target are ignored, so a connector can still start or
end inside its own zone. The same options can prefer lanes that reduce
connector-to-connector crossings when reference connectors are supplied; page-wide
routing supplies the page connector set automatically and can run deterministic
page-level optimization passes so the most conflicted connectors are considered
first on later sweeps. Dense pages can also use multi-waypoint dogleg candidates
when a simple three-segment orthogonal route still crosses important content.
Pages can also set native Visio routing defaults for connectors that do not
carry local routing or line-jump settings, plus placement and layout-grid policy
used by Visio's Re-Layout Page commands.
using System.Linq;
using OfficeIMO.Visio;
using OfficeIMO.Visio.Stencils;
var doc = VisioDocument.Create("routes.vsdx");
var page = doc.AddPage("Routes");
page.PlacementStyle = VisioPlacementStyle.HierarchyLeftToRightMiddle;
page.PlacementDepth = VisioPlacementDepth.Medium;
page.PlacementFlip = VisioPlacementFlip.Horizontal | VisioPlacementFlip.Rotate90;
page.MoveShapesAwayOnDrop = true;
page.ResizePageToFitLayout = true;
page.EnableLayoutGrid = true;
page.SetLayoutGridSizing(1.2, 0.45);
page.ConnectorRouteStyle = VisioPageRouteStyle.FlowchartTopToBottom;
page.ConnectorRouteAppearance = VisioLineRouteExtension.Straight;
page.LineJumpStyle = VisioLineJumpStyle.Gap;
page.LineJumpCode = VisioLineJumpCode.DisplayOrder;
page.HorizontalLineJumpDirection = VisioHorizontalLineJumpDirection.Up;
page.VerticalLineJumpDirection = VisioVerticalLineJumpDirection.Right;
page.SetConnectorSpacing(0.25, 0.45);
var source = page.AddStencilShape(VisioStencils.Flowchart.Get("process"),
"source", 2, 5, "Source");
var target = page.AddStencilShape(VisioStencils.Flowchart.Get("process"),
"target", 7, 3, "Target");
target.PlacementStyle = VisioPlacementStyle.HierarchyLeftToRightMiddle;
target.PlacementFlip = VisioPlacementFlip.Horizontal | VisioPlacementFlip.Rotate90;
target.PlowCode = VisioShapePlowCode.Always;
target.AllowHorizontalConnectorRoutingThrough = false;
target.AllowVerticalConnectorRoutingThrough = false;
VisioConnector route = page.AddConnector(source, target, ConnectorKind.Dynamic,
VisioSide.Right, VisioSide.Left);
route.RouteStyle = VisioPageRouteStyle.FlowchartLeftToRight;
route.RouteAppearance = VisioLineRouteExtension.Curved;
route.LineJumpStyle = VisioLineJumpStyle.Square;
route.LineJumpCode = VisioConnectorLineJumpCode.Always;
route.HorizontalJumpDirection = VisioHorizontalLineJumpDirection.Up;
route.VerticalJumpDirection = VisioVerticalLineJumpDirection.Right;
route.RerouteBehavior = VisioConnectorRerouteBehavior.OnCrossover;
route
.RouteOrthogonal(VisioConnectorRouteStyle.HorizontalThenVertical)
.PlaceLabel(0.65, offsetY: 0.18)
.ApplyStyle(VisioStyleTheme.Modern().Connector);
page.SelectConnectedConnectors(source)
.RouteThrough(VisioConnectorWaypoint.At(4.5, 5),
VisioConnectorWaypoint.At(4.5, 3))
.Label("handoff")
.LabelPosition(0.6, offsetX: 0.15);
page.RouteConnectorsOrthogonalAroundShapes(new VisioConnectorRoutingOptions {
Padding = 0.12,
MaxLanes = 16,
IncludeContainers = true,
IncludeBackgroundSurfaces = true,
AvoidConnectorCrossings = true
});
doc.Save();
Timeline roadmaps
The timeline builder creates date-scaled roadmap diagrams with milestone semantics, above/below placement, stacked labels, and span lanes. It is useful for release plans, migration schedules, project phases, and executive roadmap views where the author should provide dates, not hand-place every marker.
using OfficeIMO.Visio;
using OfficeIMO.Visio.Diagrams;
VisioDocument.Create("roadmap.vsdx")
.TimelineDiagram("Product Roadmap", timeline => timeline
.Title()
.Theme(VisioStyleTheme.Modern())
.Range(new DateTime(2026, 1, 1), new DateTime(2026, 6, 30))
.Span("discovery", new DateTime(2026, 1, 8), new DateTime(2026, 2, 20), "Discovery")
.Span("build", new DateTime(2026, 2, 21), new DateTime(2026, 5, 15), "Build", lane: 1)
.Release("preview", new DateTime(2026, 5, 20), "Public preview", VisioTimelinePlacement.Below)
.Milestone("ga", new DateTime(2026, 6, 25), "GA")
.Callout("build", "build-note", "Implementation runway", VisioSide.Top))
.Save();
Timeline callouts can target either milestone IDs or span IDs, so roadmap notes stay attached to the dated item they explain. They can be placed by coordinates or relative to the target side.
Visual quality checks and gallery output
Package validation proves the .vsdx structure is sound. Visual quality checks
catch common diagram problems before a human opens Visio: shapes outside the
page, overlapping shapes, routed connectors crossing unrelated shapes, and
connector labels placed off-page, over unrelated shapes, or on top of each
other.
using OfficeIMO.Visio;
var results = VisioGallery.Create("gallery");
foreach (var result in results) {
if (!result.IsClean) {
foreach (var issue in result.QualityIssues) {
Console.WriteLine(issue);
}
}
}
var proofOptions = new VisioGalleryOptions {
ValidateWithVisioDesktop = true,
DesktopValidationOptions = VisioDesktopValidationOptions.RoundTripWithSvg()
};
var proofResults = VisioGallery.Create("gallery-proof", proofOptions);
// Gallery coverage includes identity/authentication, privileged access review,
// Kubernetes/service mesh, application dependency, data-platform lineage,
// hybrid network operations, process governance, incident sequence, and network segmentation
// scenarios with validation metadata.
var issues = doc.AnalyzeVisualQuality(new VisioDiagramQualityOptions {
RequireConnectorLabels = false,
CheckConnectorLabelOverlaps = true,
CheckConnectorLabelShapeOverlaps = true
});
var report = doc.GetVisualQualityReport();
doc.EnsureVisualQuality(minimumSeverity: VisioDiagramQualityIssueSeverity.Warning);
page.ResolveConnectorLabelOverlaps();
doc.PolishDiagrams();
zoneShape.MarkAsBackgroundSurface();
captionShape.MarkAsGeneratedDiagramAdornment();
The reusable gallery includes data-driven CI/CD inventory, identity
authentication, privileged-access review, Kubernetes service-mesh,
application-dependency, data-platform lineage, hybrid network operations, and
process governance review graphs built from
VisioGraphNodeRecord, VisioGraphEdgeRecord, and VisioGraphClusterRecord
records. They use first-party stencil catalogs, generated clusters, Shape Data,
hyperlinks, and automatic graph legends, so the gallery exercises real
inventory-to-diagram workflows rather than only coordinate-authored examples.
Showcase runs can also write reviewable proof metadata for generated packages,
previews, inspection snapshots, stencil-profile summaries, and visual-quality summaries, including
top-level proof and evidence totals, structural shape/connector counts, Shape Data key counts,
native/desktop preview evidence, connector Shape Data key counts, semantic-kind counts,
stencil-backed/basic-geometry mix, connection-point coverage, parsed
visual-quality quality.* counts, clean visual-quality totals, and stencil provenance.
VisioShowcaseSummary emits Markdown, JSON, and browsable HTML artifacts, and
EnsureArtifactsValid(...) recomputes file sizes and SHA-256 hashes so stale
or modified proof files fail before they are published. The HTML gallery includes
a review index with stable diagram deep links, headline proof metrics, compact
SHA-256 fingerprints with the full hash available on hover, visual-quality proof
links parsed from .visual-quality.txt artifacts, and stencil catalog proof
summaries parsed from .stencil-profile.txt artifacts. It also includes
proofTotals, evidenceTotals, shape/connector/Shape Data rollups,
stencil-backed/basic-geometry mix, connection-point coverage, native/desktop
preview completeness, clean visual-quality totals, complete structural proof, complete review proof, and a stencil coverage table
so reviewers can see both overall generated coverage and which diagrams exercise
each catalog. The JSON output includes schemaVersion, artifactCount,
proofTotals, evidenceTotals, stencilCatalogCoverage, and per-diagram
proofSummary / evidence fields for downstream CI/review tooling:
var summary = VisioShowcaseSummary.Create(
"gallery-proof",
Directory.EnumerateFiles("gallery-proof", "*.vsdx"),
Directory.EnumerateFiles(Path.Combine("gallery-proof", "Native Preview"), "*.*"),
proofFiles: Directory.EnumerateFiles(Path.Combine("gallery-proof", "Structural Proof"), "*.txt"));
summary.EnsureArtifactsValid(requirePreviewsPerDiagram: true, requireProofsPerDiagram: true);
summary.SaveArtifacts();
EnsureVisualQuality(...) throws VisioDiagramQualityException with the
blocking issues, which makes it practical to use generated diagrams in tests or
CI without writing custom issue-loop code.
Inspection snapshots and structural diffs
Inspection snapshots give tests, review tools, and stencil/profile tooling a deterministic view of a generated or loaded diagram without requiring Visio desktop automation. The snapshot includes document metadata, pages, masters, shapes, connectors, Shape Data, User cells, semantic OfficeIMO tags, layers, waypoints, and stable text output.
using OfficeIMO.Visio;
VisioInspectionSnapshot before = doc.CreateInspectionSnapshot();
string snapshotText = before.ToText();
// ... change, reload, or regenerate the diagram ...
VisioInspectionSnapshot after = doc.CreateInspectionSnapshot();
VisioInspectionDiff diff = before.Diff(after);
if (diff.HasDifferences) {
Console.WriteLine(diff.ToText());
}
VisioStencilProfile profile = after.CreateStencilProfile();
Console.WriteLine(profile.ToText());
Use inspection snapshots alongside package validation and optional PNG/SVG
preview baselines: the snapshot explains what changed structurally, while the
stencil profile reports how much of the diagram is generated-master,
package-backed, or basic-geometry driven. Stencil placement stamps catalog,
category, stencil id, tags, and source package path into shape/master metadata,
so package-backed and generated-stencil profiles survive reloads and can audit
saved files as well as in-memory documents. The rendered preview proves how the
diagram looks. The premium baseline lane also stores approved inspection and
stencil-profile text snapshots for each rendered diagram. PNG drift writes
expected, actual, and .diff.png artifacts with changed-pixel counts, while
inspection/profile drift writes expected, actual, and .diff.txt artifacts so
reviewers can distinguish renderer-only churn from structural or stencil usage
changes. SVG previews use canonicalized text comparison to account for Visio's
generated CSS class names. A no-Visio premium baseline lane also compares
first-party native SVG and PNG output for representative gallery diagrams, so
renderer drift can be caught on machines that do not have Microsoft Visio
installed.
Headless SVG and PNG export
OfficeIMO Visio can render generated pages directly to SVG or PNG without Microsoft Visio desktop automation. These headless paths are intended for CI artifacts, documentation previews, web galleries, and quick inspection of generated diagrams:
using OfficeIMO.Visio;
VisioDocument document = VisioDocument.Create("pipeline.vsdx");
VisioPage page = document.AddPage("Pipeline").Size(8, 4);
VisioShape build = page.AddProcess(1.5, 2, 1.4, 0.7, "Build");
VisioShape ship = page.AddProcess(5.5, 2, 1.4, 0.7, "Ship");
page.AddConnector(build, ship, ConnectorKind.RightAngle, VisioSide.Right, VisioSide.Left).EndArrow = EndArrow.Arrow;
string svg = document.ToSvg();
document.SaveAsSvg("pipeline.svg", new VisioSvgSaveOptions {
PixelsPerInch = 96,
BackgroundColor = null
});
byte[] png = document.ToPng(new VisioPngSaveOptions {
PixelsPerInch = 144,
Supersampling = 3,
FontFilePath = "path/to/font.ttf"
});
document.SaveAsPng("pipeline.png");
The native SVG renderer covers OfficeIMO-authored shapes, connectors, labels,
bounded text wrapping/scaling with long-word breaks, styled underline/italic attributes, text rotation, rotated styled text-block backgrounds with Visio
transparency, connector-label backgrounds, render-time connector-label overlap
avoidance including endpoint-shape, dense-label clearance, and connector-line crossing avoidance, metadata-driven
first-party stencil pictograms with authored shape rotation for straight and curved glyphs, text styles, common
flowchart geometry, simple preserved Visio MoveTo/LineTo/PolylineTo and relative
geometry-row outlines with intra-section subpath breaks and unclosed NoFill open
paths, deleted Geometry/SplineKnot rows, simple preserved Width/Height/LocPinX/LocPinY/PinX/PinY/Angle/MIN/MAX/ABS/SQRT/PI/SIN/COS/TAN/ATAN/ATAN2/RAD/DEG/INT/POW/^/ROUND/AND/OR/NOT/GUARD/IF formulas including POLYLINE arguments and percentage plus angle/length unit-suffixed numeric literals,
preserved NoFill/NoLine/NoShow geometry flags, scaled master/master-shape
preserved outlines, preserved Ellipse and open clipped InfiniteLine rows,
flattened preserved ArcTo/EllipticalArcTo, RelEllipticalArcTo,
CubBezTo/QuadBezTo, and RelCubBezTo/RelQuadBezTo,
SplineStart/SplineKnot, plus NURBSTo
formula outlines with Visio compact knot-vector expansion,
transparency, dashed strokes, semantic database/storage cylinder bodies, semantic flowchart start/end terminator capsules, semantic document stencil wavy bottoms, built-in chevron polygons, delay D-shapes, and manual input slanted quadrilaterals, color/opacity-matching inline arrowheads, and rotated browser-renderable package-backed preview/icon payloads, including content-sniffed generic media relationships, when
package masters expose embedded PNG/JPG/GIF/SVG media. The native PNG renderer uses the same
OfficeIMO-authored geometry surface and writes PNG bytes directly, including
basic anti-aliased shapes with authored ellipse rotation, semantic database/storage cylinder bodies, semantic flowchart start/end terminator capsules, semantic document stencil wavy bottoms, built-in chevron polygons, delay D-shapes, and manual input slanted quadrilaterals, dashed shape/connector strokes, connectors, arrows,
wrapped labels and long unspaced shape text, styled text-block backgrounds, metadata-driven first-party
stencil pictograms with authored shape rotation for straight and curved glyphs, embedded package PNG preview/icon payloads including content-sniffed generic media relationships, truecolor, indexed-palette, grayscale, and
grayscale-alpha PNGs, including packed 1/2/4-bit indexed/grayscale icons and
16-bit channel payloads downsampled into the native preview buffer, honoring
palette and truecolor tRNS transparency, with
aspect-preserving placement and shape rotation, managed TrueType/OpenType outline text from a
configured FontFilePath/FontCollectionIndex/FontFaceName or from managed
default font-file discovery where available, styled text underlines/italics, TextAngle rotation, rotated styled text-block backgrounds, a small stroke-font fallback, and optional
transparent backgrounds. The PNG writer uses managed DEFLATE
compression, shares the same render-time connector-label overlap avoidance
including endpoint-shape, dense-label clearance, and connector-line crossing avoidance, and does not call operating-system
graphics or font APIs. Set
ResolveConnectorLabelOverlaps = false when a preview must preserve authored
label pins exactly, or
RenderStencilArtwork = false when the native SVG/PNG preview should show only
the authored shape geometry. Desktop Visio export remains the higher-fidelity
proof path for complex Visio-authored content, non-PNG package media in native
PNG, native master/vector geometry, and final visual parity. The no-Visio native
baseline lane now covers all eight premium gallery diagrams so renderer drift is
gated without requiring Microsoft Visio.
Native stencil catalogs
Built-in stencil catalogs give you reusable, searchable shape definitions while
still generating masters from OfficeIMO code. They are not .vssx or .vsdx
runtime dependencies. Use Get(...) for exact known shapes and Search(...)
or InCategory(...) when you want user-friendly discovery by id, name, master,
category, keyword, alias, or tag. Each stencil also carries IconNameU preview
metadata for palette and picker UIs.
The built-in catalog set covers basic, flowchart, block-diagram, architecture, network, infrastructure, cloud, security/identity, containers/Kubernetes, data/platform, collaboration/business process, sequence, swimlane, org-chart, and timeline domains. These first-party definitions are dependency-free and preserve searchable domain intent in inspection snapshots and stencil profiles.
using OfficeIMO.Visio;
using OfficeIMO.Visio.Stencils;
var doc = VisioDocument.Create("stencils.vsdx");
var page = doc.AddPage("Catalog");
var process = page.AddStencilShape(VisioStencils.Flowchart.Get("process"),
"receive", 2, 4, "Receive request");
var decision = page.AddStencilShape(VisioStencils.Flowchart, "branch",
"approved", 5, 4, "Approved?");
var switchShape = page.AddStencilShape("net.switch", "switch", 8, 6, "Switch");
var dataStore = VisioStencils.All.Search("data-store").First();
var identityProvider = VisioStencils.SecurityIdentity.Get("idp");
var kubernetesCluster = VisioStencils.ContainersKubernetes.Get("kubernetes");
var dataPipeline = VisioStencils.DataPlatform.Get("etl");
var networkShapes = VisioStencils.All.InCategory("Network");
var custom = VisioStencilCatalog.Create("Custom Infrastructure", catalog => catalog
.Add("custom.cache", "Cache", "Process", "Infrastructure", 1.8, 0.9, "redis")
.AddWithMetadata("custom.archive", "Object Archive", "Data", "Infrastructure",
1.8, 0.9,
keywords: new[] { "blob" },
aliases: new[] { "object-store" },
tags: new[] { "cloud", "storage" },
iconNameU: "Data"));
var cache = page.AddStencilShape(custom, "redis", "cache", 8, 4, "Cache");
var packageCatalog = VisioStencilPackageCatalog.Load("network.vssx",
new VisioStencilPackageLoadOptions {
Category = "Network",
MasterNames = new[] { "Server", "rId4", "database-cylinder" },
LearnMasterDimensions = true,
IncludeUnsupportedMasters = false
});
custom.Save("infrastructure.officeimo-visio-stencils.xml");
var reusable = VisioStencilCatalog.Load("infrastructure.officeimo-visio-stencils.xml");
page.AddConnector(process, decision, ConnectorKind.Dynamic,
VisioSide.Right, VisioSide.Left);
doc.Save();
VisioStencilPackageCatalog.Load(...) reads master metadata from .vsdx,
.vssx, .vstx, and the macro-enabled package variants. It does not use those
files as runtime templates. The MasterNames filter can target the universal
name, visible name, relationship id, numeric id, or normalized slug discovered in
the package. Package catalogs can learn native master dimensions, preview/icon
image relationship metadata, and native connection points; when a package-backed
stencil is placed, those connection points are scaled onto the page shape so
connectors, inspection snapshots, and stencil profiles can see the real stencil
attachment profile.
When you want real external artwork, load the package catalog with
IncludeUnsupportedMasters = true and place shapes from that catalog. Package
catalog shapes retain their SourcePackagePath, so AddStencilShape(...)
auto-imports the required raw master XML, relationships, media, colors, styles,
fonts, and theme into the generated .vsdx:
using OfficeIMO.Visio;
using OfficeIMO.Visio.Stencils;
var catalog = VisioStencilPackageCatalog.Load("Azure.vssx",
new VisioStencilPackageLoadOptions {
IncludeUnsupportedMasters = true
});
var doc = VisioDocument.Create("external-stencils.vsdx");
var page = doc.AddPage("Architecture", 14, 8.5);
var api = page.AddStencilShape(catalog.Get("API Management"), "api", 2, 5);
var queue = page.AddStencilShape(catalog.Search("Service Bus").First(), "queue", 5, 5);
page.AddConnector(api, queue, ConnectorKind.Straight, VisioSide.Right, VisioSide.Left);
doc.Save();
Use LoadMany(...) or LoadDirectory(...) to compose a palette from many packs.
That is the preferred model for repository-style stencil packs, such as the
Microsoft Integration and Azure community pack, where the useful masters are
spread across multiple .vssx files:
var packages = VisioStencilPackageCatalog.EnumeratePackageFiles(
@"C:\StencilPacks\Microsoft-Integration-and-Azure-Stencils-Pack-for-Visio",
recursive: true);
var integration = VisioStencilPackageCatalog.LoadMany(packages,
new VisioStencilPackageLoadOptions {
CatalogName = "Microsoft Integration and Azure",
IncludeUnsupportedMasters = true
});
var apim = integration.Search("API Management").First();
var serviceBus = integration.Search("Service Bus").First();
To inspect a pack before building a diagram, render a catalog contact sheet:
var doc = VisioDocument.Create("stencil-gallery.vsdx");
var page = doc.AddPage("Gallery", 11, 8.5);
page.AddStencilGallery(integration, new VisioStencilGalleryOptions {
Title = "Microsoft Integration and Azure",
Columns = 4,
MaxShapes = 24,
IncludeStencilMetadataShapeData = true
});
doc.Save();
For a complete catalog review artifact, create a paginated gallery document. It adds an overview page, splits large catalogs by category, and stamps each preview shape with Shape Data rows such as stencil id, category, catalog, master, keywords, aliases, tags, default size, source package, preview image, and connection-point counts where available:
var gallery = VisioStencilGalleryDocument.Create("stencil-gallery.vsdx",
integration,
new VisioStencilGalleryDocumentOptions {
Title = "Microsoft Integration and Azure review",
Columns = 4,
ShapesPerPage = 24,
IncludeStencilMetadataShapeData = true
});
gallery.Save();
For package-backed masters that carry embedded preview/icon payloads, export a reviewable HTML inventory and the raw image payloads:
var previewGallery = VisioStencilPackageCatalog.CreatePreviewGallery(
@"C:\StencilPacks\Azure.vssx",
@"C:\Temp\AzureStencilPreview",
new VisioStencilPackageLoadOptions {
IncludeUnsupportedMasters = true
},
new VisioStencilPreviewGalleryOptions {
Title = "Azure stencil preview review"
});
Console.WriteLine(previewGallery.IndexPath);
Browser-friendly payloads such as PNG, JPG, SVG, GIF, BMP, and WebP render
inline in the generated index. Other native Visio/Office payloads such as EMF
are still extracted and listed with their content type, relationship target,
byte length, and saved file link for external review tools. Browser-renderable
payloads also receive deterministic SVG thumbnail wrappers in the thumbnails
directory by default, so catalog review output has stable visual artifacts that
can be archived or diffed beside the raw embedded media.
DiscoverInstalledVisioPackages() finds the local Microsoft Visio .vssx and
.vstx content folders without automating Visio, letting you build diagrams from
installed Visio stencils while keeping OfficeIMO itself dependency-free:
var installed = VisioStencilPackageCatalog.DiscoverInstalledVisioPackages()
.Where(path => Path.GetFileName(path).StartsWith("AZURE", StringComparison.OrdinalIgnoreCase));
var azure = VisioStencilPackageCatalog.LoadMany(installed,
new VisioStencilPackageLoadOptions {
CatalogName = "Installed Azure Stencils",
IncludeUnsupportedMasters = true
});
VisioStencilCatalog.Save(...) and VisioStencilCatalog.Load(...) persist
OfficeIMO-native catalog metadata as a small XML manifest. This is useful for
reusable first-party or application-specific palettes without requiring Visio
stencil packages at runtime. The manifest preserves source package paths,
preview metadata, learned default sizes, and learned source connection points.
Query and selection editing
Query helpers let you edit diagrams by meaning instead of by page indexes. They work with generated and loaded shapes, including nested group children.
using OfficeIMO.Visio;
using OfficeIMO.Visio.Stencils;
using Color = OfficeIMO.Drawing.OfficeColor;
var doc = VisioDocument.Create("editing.vsdx");
var page = doc.AddPage("Ownership");
var intake = page.AddStencilShape(VisioStencils.Flowchart.Get("process"),
"intake", 2, 5, "Receive");
var review = page.AddStencilShape(VisioStencils.Flowchart.Get("process"),
"review", 5, 5, "Review");
var decision = page.AddStencilShape(VisioStencils.Flowchart.Get("decision"),
"approved", 8, 5, "Approved?");
page.AddConnector(intake, review, ConnectorKind.Dynamic, VisioSide.Right, VisioSide.Left);
page.AddConnector(review, decision, ConnectorKind.Dynamic, VisioSide.Right, VisioSide.Left);
intake.Data["Owner"] = "Ops";
review.Data["Owner"] = "Ops";
page.SelectWithData("Owner", "Ops")
.Fill(Color.LightBlue)
.Stroke(Color.DodgerBlue, 0.02)
.Duplicate(new VisioShapeDuplicationOptions {
OffsetX = 1.5,
OffsetY = -0.75,
IdSuffix = "-copy",
ConnectorIdSuffix = "-copy"
});
page.SelectOutgoingConnectors(review)
.LineColor(Color.DodgerBlue)
.EndArrow(EndArrow.Triangle);
page.SelectContainedIn(page.ShapesWithData("Owner", "Ops").First().GetShapeBounds())
.ShapeData("ReviewScope", "Operations");
page.SelectConnectedComponent(review)
.ShapeData("Component", "Approval");
page.SelectWithShapeData("Risk", value => int.TryParse(value, out int risk) && risk >= 4)
.Stroke(Color.Red, 0.025);
doc.Save();
Selection duplication remaps copied shape identifiers and duplicates only the
connectors whose endpoints are both inside the copied selection. Shape styling,
layers, hyperlinks, User cells, typed Shape Data, protection, layout hints, and
connector routing metadata move with the copy. VisioShapeDuplicationOptions
lets callers control offsets, connector copying, semantic ID suffixes, and
advanced shape/connector ID factories without adding serializer or reflection
dependencies.
Fluent page editing exposes the same copy workflow with friendly default
-copy identifiers, so duplicated shapes remain addressable in the same chain:
document.AsFluent()
.ExistingPage("Operations", page => page
.DuplicateShapes(new[] { "api", "database" }, copies => copies
.ShapeData("Copied", "Yes"))
.Shape("api-copy", shape => shape.Text("API copy"))
.Connect("api-copy", "database-copy", VisioSide.Right, VisioSide.Left,
connector => connector.Label("copied route")));
The same query surface supports editing loaded diagrams by geometry and graph
structure: ShapesIntersecting(...), ShapesContainedIn(...),
ShapesWithShapeData(...), ConnectedComponent(...), and PathBetween(...) can find contained shapes,
overlapping annotations, connected islands, and shortest connected paths before
applying bulk style or metadata edits.
Whole pages can be duplicated as well. The copy receives fresh shape and connector IDs while keeping page settings, layers, background-page linkage, shape metadata, internal connectors, labels, and explicit routes:
VisioPage reviewPage = page.Duplicate("Review copy");
VisioPage independentReviewPage = page.Duplicate(new VisioPageDuplicationOptions {
Name = "Review copy",
DuplicateBackgroundPage = true,
BackgroundPageName = "Review background copy"
});
Existing shapes can also be retargeted to a different generated master without losing their editing metadata or connector endpoints:
page.SelectByMaster("Process")
.ReplaceMaster(VisioStencils.Flowchart.Get("decision"), resizeToMaster: true);
page.ReplaceMaster(archiveShape, "Data");
Layers
Pages support Visio-native layers. Shapes and connectors can belong to one or
more layers; OfficeIMO writes the page Layer section and the shape
LayerMember cells directly, so the document opens in Visio with editable
layer membership.
using OfficeIMO.Visio;
using OfficeIMO.Visio.Stencils;
using Color = OfficeIMO.Drawing.OfficeColor;
var doc = VisioDocument.Create("layers.vsdx");
var page = doc.AddPage("Layered");
page.AddLayer("Infrastructure");
page.AddLayer("Annotations").Print = false;
var server = page.AddStencilShape(VisioStencils.Network.Get("server"),
"server", 2, 5, "Server");
var note = page.AddStencilShape(VisioStencils.BasicShapes.Get("rectangle"),
"note", 5, 5, "Internal note");
page.AddToLayer("Infrastructure", server)
.AddToLayer("Annotations", note);
page.SelectLayer("Infrastructure")
.Stroke(Color.DodgerBlue, 0.02);
doc.Save();
Hyperlinks
Shapes and connectors can carry native Visio hyperlink rows. OfficeIMO writes
the ShapeSheet Hyperlink section directly and loads it back into typed
VisioHyperlink objects, while preserving unknown hyperlink cells from files
created elsewhere.
using OfficeIMO.Visio;
using Color = OfficeIMO.Drawing.OfficeColor;
var doc = VisioDocument.Create("hyperlinks.vsdx");
var page = doc.AddPage("Linked");
var portal = page.AddRectangle(2, 5, 2, 1, "Portal");
var api = page.AddRectangle(5, 5, 2, 1, "API");
portal.AddHyperlink("https://github.com/EvotecIT/OfficeIMO", "Repository");
var connector = page.AddConnector(portal, api, ConnectorKind.Dynamic, VisioSide.Right, VisioSide.Left);
connector.AddHyperlink("https://example.org/openapi.json", "API contract");
page.SelectWithHyperlinks()
.Fill(Color.LightYellow)
.Stroke(Color.DodgerBlue, 0.02);
page.SelectConnectorsWithHyperlinks()
.EndArrow(EndArrow.Triangle);
doc.Save();
Shape Data
Shapes support typed Visio Shape Data rows in the ShapeSheet Prop section.
The simple Data dictionary still works, while SetShapeData lets you keep
labels, prompts, types, formats, sort keys, and other metadata visible in
Visio's Shape Data window.
using OfficeIMO.Visio;
using Color = OfficeIMO.Drawing.OfficeColor;
var doc = VisioDocument.Create("shape-data.vsdx");
var page = doc.AddPage("Shape Data");
var api = page.AddRectangle(2.5, 4, 2.2, 1, "API");
api.SetShapeData("Owner", "Platform", "Owner",
VisioShapeDataType.String, "Owning support team");
api.SetShapeData("MonthlyCost", "1250", "Monthly cost",
VisioShapeDataType.Currency, "Estimated monthly cost", "$#,##0");
var database = page.AddRectangle(6, 4, 2.2, 1, "Database");
database.SetShapeData("Owner", "Data", "Owner",
VisioShapeDataType.String, "Owning support team");
page.SelectWithShapeData("Owner", "Platform")
.Fill(Color.LightBlue)
.ShapeData("Reviewed", "Yes", "Reviewed",
VisioShapeDataType.Boolean, "Architecture review complete");
doc.Save();
For repeatable metadata across generated or loaded diagrams, define a reusable schema and apply it to shapes, shape selections, connectors, or connector selections. Existing values are preserved by default while labels, prompts, types, list formats, sort keys, visibility, and verification settings are standardized.
var schema = VisioShapeDataSchema.Create()
.Field("Owner", "Owner", VisioShapeDataType.String,
defaultValue: "Unassigned", prompt: "Owning team",
sortKey: "010", required: true)
.Field("Risk", "Risk", VisioShapeDataType.FixedList,
defaultValue: "Medium", prompt: "Operational risk",
sortKey: "020", required: true, verify: true,
allowedValues: new[] { "Low", "Medium", "High" })
.Field("MonthlyCost", "Monthly cost", VisioShapeDataType.Currency,
defaultValue: "0", prompt: "Estimated monthly run cost",
format: "$#,##0", sortKey: "030");
schema.ApplyTo(api);
page.SelectWithShapeData("Owner", value => string.IsNullOrWhiteSpace(value))
.ShapeData(schema);
var issues = schema.Validate(api);
Shape Data can also be surfaced as visible data graphics. Generated badges and bars are stored as diagram adornments tied back to the target shape and source field, so routing, quality checks, inspection snapshots, and stencil profiles can distinguish them from business shapes.
api.SetShapeData("Status", "Healthy", "Status",
VisioShapeDataType.FixedList, format: "Healthy;Warning;Critical");
api.SetShapeData("Slo", "72", "SLO", VisioShapeDataType.Number);
var dataGraphic = VisioDataGraphic.Create()
.Badge("Status")
.Bar("Slo", maximumValue: 100, label: "SLO");
page.SelectWithShapeData("Status", value => !string.IsNullOrWhiteSpace(value))
.AddDataGraphics(dataGraphic);
Page settings
Pages expose common print and page-management cells without requiring raw ShapeSheet XML: margins, print orientation, page replacement/duplication locks, drawing size behavior, automatic page resizing, shape splitting, and whether a page is visible in Visio page lists.
using OfficeIMO.Visio;
var doc = VisioDocument.Create("page-settings.vsdx");
var page = doc.AddPage("Print ready", 11, 8.5);
page.SetMargins(0.4, 0.5, 0.6, 0.7);
page.PrintOrientation = VisioPagePrintOrientation.Landscape;
page.PageLockReplace = true;
page.DrawingSizeType = VisioDrawingSizeType.Custom;
page.AutoResizeDrawing = false;
page.AllowShapeSplitting = false;
page.UiVisibility = VisioPageUiVisibility.Normal;
page.AddRectangle(5.5, 4.25, 2.4, 1, "Print-ready page");
doc.Save();
Background pages
Reusable Visio background pages can hold title bands, watermarks, legends, page
frames, or locked diagram furniture once, then foreground pages can reference
them with native BackPage links.
using OfficeIMO.Visio;
using Color = OfficeIMO.Drawing.OfficeColor;
var doc = VisioDocument.Create("background-pages.vsdx");
var background = doc.AddBackgroundPage("Brand background", 11, 8.5);
background.AddRectangle(5.5, 8.05, 10.5, 0.45, "OfficeIMO generated")
.Protect(p => p.Size().Position().Text().Selection())
.FillColor = Color.LightBlue;
var architecture = doc.AddPage("Architecture", 11, 8.5);
architecture.SetBackgroundPage(background);
architecture.AddRectangle(3.5, 4.8, 2.2, 1, "API");
architecture.AddRectangle(7.5, 4.8, 2.2, 1, "Worker");
var operations = doc.AddPage("Operations", 11, 8.5);
operations.SetBackgroundPage(background);
operations.AddRectangle(5.5, 4.8, 2.2, 1, "Runbook");
doc.Save();
Shape protection
Shapes and connectors expose native Visio Lock* ShapeSheet cells for diagrams
that should open cleanly in Visio but protect generated scaffolding and routed
connectors from accidental edits. Protection round-trips from existing .vsdx
files and works with selections.
using OfficeIMO.Visio;
using Color = OfficeIMO.Drawing.OfficeColor;
var doc = VisioDocument.Create("protected-diagram.vsdx");
var page = doc.AddPage("Protected Diagram");
var background = page.AddRectangle(4.25, 3, 7.5, 4.8, "Generated zone");
background.FillColor = Color.LightCyan;
background.Protect(p => p.Size().Position().Selection().Formatting());
var api = page.AddRectangle(3, 3.8, 2, 1, "API");
api.SetShapeData("Owner", "Platform");
var db = page.AddRectangle(6, 3.8, 2, 1, "Database");
var link = page.AddConnector(api, db, ConnectorKind.Dynamic,
VisioSide.Right, VisioSide.Left);
link.Label = "read";
link.Protect(p => p.Endpoints().Text().Deletion());
page.SelectWithData("Owner", "Platform")
.Protect(p => p.Text().Deletion())
.Fill(Color.LightYellow);
page.SelectConnectorsWithProtection()
.Protect(p => p.Formatting());
doc.Save();
Containers and User cells
Pages can create Visio-native containers around existing shapes. OfficeIMO
writes the ShapeSheet User section and Relationships cells directly, so
containers open as semantic Visio structures rather than as decorative boxes.
Generic User cells are also available for custom ShapeSheet metadata.
using OfficeIMO.Visio;
using OfficeIMO.Visio.Stencils;
using Color = OfficeIMO.Drawing.OfficeColor;
var doc = VisioDocument.Create("containers.vsdx");
var page = doc.AddPage("Application");
var api = page.AddStencilShape(VisioStencils.Network.Get("server"),
"api", 3, 5.5, "API");
var worker = page.AddStencilShape(VisioStencils.Network.Get("server"),
"worker", 6, 5.5, "Worker");
var tier = page.AddContainer("app-tier", "Application tier",
new[] { api, worker },
new VisioContainerOptions {
Margin = 0.35,
FillColor = Color.LightCyan,
LineColor = Color.DodgerBlue
});
tier.SetUserCell("OfficeIMO.Role", "Tier", "STR", prompt: "Semantic role");
page.SelectContainers()
.Stroke(Color.DodgerBlue, 0.02);
page.SelectWithUserCell("OfficeIMO.Role", "Tier")
.UserCell("OfficeIMO.Reviewed", "Yes", "STR");
doc.Save();
Callouts and annotations
Pages can add semantic callouts with leader connectors. OfficeIMO writes normal editable Visio shapes and connectors, plus User cells that make callouts easy to find again after loading.
using OfficeIMO.Visio;
var api = page.AddProcess(4, 4.5, 2, 1, "API");
var note = page.AddCallout(api, "api-note", "Check retry policy", 7.5, 6,
new VisioCalloutOptions {
Width = 2.4,
Height = 0.8,
RouteOffset = 0.15
});
var autoNote = page.AddCallout(api, "sla-note", "Review SLA target",
VisioSide.Right, gap: 0.35);
page.SelectCallouts()
.LockPosition();
doc.Save();
Use the coordinate overload when you need exact placement, or the side-based overload when the callout should sit to the left, right, top, or bottom of the target shape without hand-calculating page coordinates.
Text styling
Text blocks can be styled with a reusable object or applied to selections. The
same style model works for shape text and connector labels. Styles are saved
into Visio ShapeSheet text block cells plus Char and Para sections, so text
remains editable in Visio.
using OfficeIMO.Visio;
using Color = OfficeIMO.Drawing.OfficeColor;
var textStyle = new VisioTextStyle {
FontFamily = "Aptos",
Color = Color.FromRgb(0x33, 0x66, 0x99),
Size = 12,
Bold = true,
HorizontalAlignment = VisioTextHorizontalAlignment.Center,
VerticalAlignment = VisioTextVerticalAlignment.Middle,
LeftMargin = 0.08,
RightMargin = 0.08,
TextPinY = -0.2,
TextHeight = 0.4,
BackgroundColor = Color.LightYellow,
BackgroundTransparency = 20
};
page.AddProcess(2, 4, 2.5, 1, "Approve")
.ApplyTextStyle(textStyle);
page.SelectWithData("Lane", "Finance")
.ApplyTextStyle(textStyle);
var connector = page.AddConnector(source, target, ConnectorKind.Dynamic, VisioSide.Right, VisioSide.Left);
connector.Label = "Approved";
connector
.PlaceLabel(0.55, offsetY: 0.18)
.ApplyTextStyle(new VisioTextStyle {
FontFamily = "Aptos",
Color = Color.DodgerBlue,
Size = 9,
Bold = true,
HorizontalAlignment = VisioTextHorizontalAlignment.Center,
BackgroundColor = Color.White,
BackgroundTransparency = 0
});
page.SelectConnectedConnectors(source)
.ApplyTextStyle(textStyle);
doc.Save();
Layout cleanup helpers
Selections can also be aligned, distributed, resized to text, centered, and fit
to page bounds. Page fitting and centering include explicit connector waypoints
and connector label boxes, so routed labels do not get clipped. Text sizing uses
the deterministic OfficeIMO.Drawing measurement engine, so it works without
system font APIs. Connector labels can also be moved deterministically away
from page edges, unrelated shapes, and connector labels. The cleanup can slide
labels along their connector path before falling back to page-coordinate
offsets, runs whole-page label optimization passes that revisit the most
conflicted labels first, and ignores generated adornment captions, so premium
zone headers do not push legitimate connector labels around. It can also prefer
connector labels inside the shared zone of their endpoints and away from
unrelated background zones when premium zone diagrams need stronger label
placement hints.
It can also opt into obstacle-aware connector routing before label placement,
which is useful when a generated diagram has simple connector-to-shape
intersections.
using OfficeIMO.Drawing;
using OfficeIMO.Visio;
page.SelectWithData("Owner", "Ops")
.ResizeToText(new OfficeFontInfo("Calibri", 11))
.RelayoutAsGrid(columns: 2, horizontalSpacing: 0.4, verticalSpacing: 0.3)
.Align(VisioVerticalAlignment.Middle);
page.SelectByMaster("Decision")
.Align(VisioHorizontalAlignment.Center);
doc.AsFluent()
.ExistingPage("Workflow", p => p
.RelayoutShapesAsGrid(new[] { "review", "approve", "archive" }, layout => {
layout.Columns = 3;
layout.HorizontalSpacing = 0.4;
layout.RouteInternalConnectors = true;
})
.RelayoutContainerMembers("runtime-tier", layout => {
layout.Columns = 1;
layout.VerticalSpacing = 0.25;
}));
page.SelectConnectedConnectors(page.FindShapeById("approved")!)
.ApplyTextStyle(new VisioTextStyle { FontFamily = "Calibri", Size = 9 })
.ResizeLabelsToText(maximumWidth: 1.6);
page.PolishDiagram(new VisioDiagramPolishOptions {
ResolveShapeOverlaps = true,
ResolveConnectorShapeIntersections = true,
ConnectorRoutingObstaclePadding = 0.12,
ConnectorRoutingAvoidContainers = true,
ConnectorRoutingAvoidBackgroundSurfaces = true,
ConnectorRoutingAvoidConnectorCrossings = true,
ConnectorRoutingPageOptimizationPasses = 3,
PreferConnectorLabelsInsideEndpointZones = true,
ConnectorLabelPositionStep = 0.08,
ConnectorLabelMaxPositionShifts = 4,
ConnectorLabelOptimizationPasses = 3,
MaximumConnectorLabelWidth = 1.6,
FitHorizontalMargin = 0.6,
FitVerticalMargin = 0.45
});
doc.Save();
RelayoutAsGrid, RelayoutAsHorizontalStack, and RelayoutAsVerticalStack
are deterministic and can reroute connectors whose endpoints are both inside a
page-backed selection.
The fluent page wrapper exposes the same engine for loaded diagrams through
RelayoutShapesAsGrid, RelayoutShapesAsHorizontalStack,
RelayoutShapesAsVerticalStack, RelayoutConnectedComponentAsGrid, and
RelayoutContainerMembers, so common edit workflows can stay ID-based while
still using typed selections under the hood.
PolishDiagram can also move crowded top-level shapes apart before it resolves
connector routes, connector labels, and page fitting, which is useful when a
generated diagram has reasonable structure but still needs a final visual cleanup
pass.
Learning from VSDX fixtures
OfficeIMO can inspect .vsdx files to learn which supported masters are present,
then generate OfficeIMO-owned masters from code. The source file is a learning
fixture, not a runtime template, so generated documents stay dependency-light
and deterministic.
using OfficeIMO.Visio;
var doc = VisioDocument.Create("typed-shapes.vsdx");
doc.UseMastersByDefault = true;
doc.LearnMastersFromVsdx("DrawingWithShapes.vsdx",
new[] { "Rectangle", "Ellipse", "Diamond", "Dynamic connector" });
var page = doc.AddPage("Page-1");
page.AddRectangle(2, 2, 2, 1, "Generated from OfficeIMO");
doc.Save();
Optional native Visio validation
On Windows machines with Microsoft Visio installed, you can add a stronger desktop compatibility gate without adding a compile-time Visio dependency. OfficeIMO uses late-bound COM automation only when you call this helper.
using OfficeIMO.Visio;
VisioDesktopValidationOptions options = VisioDesktopValidationOptions.RoundTripWithSvg();
options.SaveCopyPath = "diagram.visio-roundtrip.vsdx";
options.ExportDirectory = "visio-proof";
VisioDesktopValidationResult result = VisioDesktopValidator.Validate("diagram.vsdx", options);
if (result.IsAvailable && !result.IsValid) {
throw new InvalidOperationException(string.Join(Environment.NewLine, result.Issues));
}
See OfficeIMO.Examples/Visio/* for more.
Feature Scope
- 📄 Pages: ✅ add/remove pages
- 🧱 Shapes: ✅ built-in and semantic shapes, master-backed stencil placements, groups, text, Shape Data, User cells, hyperlinks, protection, and local geometry preservation
- 🔗 Connectors: ✅ dynamic, straight, right-angle, curved, side glue, explicit waypoints, arrows, labels, routing metadata, label placement, and page-level cleanup helpers
- 🧭 Diagram builders: ✅ flowchart builder with vertical and two-column continuation layouts plus branch routing, ✅ generic graph builder with cycles, disconnected components, layered/grid/radial layouts, zones, package-backed stencil nodes, data-driven inventory/identity/Kubernetes/application dependency gallery graphs, and generated legends, ✅ block diagram builder with grid regions and data/control flows, ✅ architecture builder with infrastructure components, regions, and routed data/control/dependency flows, ✅ network builder with zones, devices, links, legends, record imports, Shape Data, and hyperlinks, ✅ sequence builder with participants, lifelines, message types, self-calls, activations, guarded/nested fragments, notes, and data-driven incident/runbook record imports, ✅ swimlane builder with lanes, phases, activities, handoffs, and exception paths, ✅ org chart builder with hierarchy, assistants, team bands, vacancies, and external roles, ✅ timeline builder with date-scaled milestones and span lanes
- 🧰 Native stencils: ✅ built-in searchable catalogs for basic, flowchart, block-diagram, architecture, network, infrastructure, cloud, security/identity, containers/Kubernetes, data/platform, collaboration/business process, sequence, swimlane, org-chart, and timeline shapes; ✅ external package catalogs with learned dimensions, preview metadata, source package provenance, and native connection points
- 🎨 Style themes: ✅ reusable shape/connector/text styles and Modern/Office/Fluent/Technical/Minimal/Dark/Print authoring presets
- 🔎 Rich editing: ✅ recursive shape queries, shape/data/text/master/layer/hyperlink selectors, connector neighbor queries, page layers, shape and connector hyperlinks, typed stencil migration maps, bulk style/data/layer/hyperlink edits, align/distribute, resize-to-text, center content, and fit-to-content
- 🖼️ Export/proof: ✅ dependency-free native SVG and PNG preview exports for OfficeIMO-authored pages; ✅ premium gallery baselines with PNG/SVG, inspection, and stencil-profile proof; ✅ showcase review proof with inspection, stencil profile, and visual-quality artifacts
- 🧩 VSDX learning fixtures: ✅ inspect supported masters without treating sample files as runtime templates
- 🧪 Validation: ✅ package/in-memory validators, visual quality analyzer, premium baseline lane, and optional Microsoft Visio desktop open, save-copy, and SVG/PNG/PDF export checks via late-bound COM
Authoring units
Pages now remember a DefaultUnit (inches by default). When you create a page
with centimeters or millimeters, shape-adding overloads use that unit implicitly,
and the fluent shape builders follow that page unit as well, so you don't need helper conversions:
var page = doc.AddPage("A4 landscape", 29.7, 21.0, VisioMeasurementUnit.Centimeters);
page.AddRectangle(4.0, 15.0, 4.0, 2.5, "Rectangle"); // all values in cm
page.AddCircle(16.0, 15.0, 3.5, "Circle"); // diameter in cm
If you prefer, you can still pass an explicit unit:
page.AddRectangle(1.5, 1.0, 2.0, 1.0, "Rect", VisioMeasurementUnit.Inches);
Connection points
You no longer need to add side connection points manually. The connector API
ensures side glue automatically when you specify VisioSide.Left/Right/Top/Bottom.
The old ensure method has been internalized.
At a glance
- Create/Load/Save .vsdx (OPC packaging)
- Build simple diagrams or data-driven premium diagrams without requiring Visio
- Fluent builder:
Page(...),Rect(...),Square(...),Ellipse(...),Circle(...),Diamond(...),Triangle(...),Connect(...) - Semantic builders for flowcharts, block diagrams, architecture, networks, topology, swimlanes, org charts, timelines, sequences, dependencies, and graphs
- Built-in and package-backed stencil catalogs with searchable metadata and typed migration maps for loaded diagrams
- Native SVG/PNG previews plus optional Microsoft Visio desktop validation/export proof
- Showcase proof summaries through
VisioShowcaseSummary, which writes Markdown, JSON, and browsable HTML artifact metadata for generated packages, previews, and review proof files, including headline proof/evidence totals plus diagram-level records/cards that pair packages with previews, SHA-256 hashes, native/desktop preview flags, inspection/stencil-profile/visual-quality proof flags, clean visual-quality and issue totals, shape/connector rollups, Shape Data key counts, semantic-kind counts, stencil-backed/basic-geometry mix, connection-point coverage, stencil provenance, complete review proof, and catalog coverage - Optional desktop preview artifacts are designed for explicit self-hosted Windows proof lanes where Microsoft Visio desktop automation is installed
Why OfficeIMO.Visio
- Server-safe VSDX generation and reading using OPC + LINQ to XML
- Diagram-first authoring APIs for real process, network, architecture, timeline, sequence, and graph scenarios
- Dependency-light core with optional Visio desktop proof only when you ask for it
- First-party stencils, premium styles, visual quality checks, and native SVG/PNG preview output for reviewable generated diagrams
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.7.2
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.7)
- OfficeIMO.Drawing (>= 1.0.16)
- System.IO.Packaging (>= 10.0.8)
-
.NETStandard 2.0
- OfficeIMO.Drawing (>= 1.0.16)
- System.IO.Packaging (>= 10.0.8)
-
net10.0
- OfficeIMO.Drawing (>= 1.0.16)
- System.IO.Packaging (>= 10.0.8)
-
net8.0
- OfficeIMO.Drawing (>= 1.0.16)
- System.IO.Packaging (>= 10.0.8)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on OfficeIMO.Visio:
| Package | Downloads |
|---|---|
|
OfficeIMO.Reader.Visio
Visio adapter for OfficeIMO.Reader using OfficeIMO.Visio inspection snapshots. |
|
|
OfficeIMO.ChartForgeX
Optional typed bridge from ChartForgeX visual artifacts to OfficeIMO Word, Excel, PowerPoint, PDF, drawing, and editable Visio surfaces. |
|
|
OfficeIMO.Visio.Pdf
First-party loss-aware Visio to PDF conversion for OfficeIMO. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.2.7 | 38 | 8/29/2026 |
| 3.2.6 | 260 | 8/22/2026 |
| 3.2.5 | 323 | 8/21/2026 |
| 3.2.4 | 305 | 8/19/2026 |
| 3.2.3 | 234 | 8/17/2026 |
| 3.2.2 | 556 | 8/13/2026 |
| 3.2.1 | 312 | 8/11/2026 |
| 3.2.0 | 415 | 8/7/2026 |
| 3.1.1 | 210 | 8/7/2026 |
| 3.1.0 | 197 | 8/6/2026 |
| 3.0.3 | 244 | 7/27/2026 |
| 3.0.2 | 192 | 7/26/2026 |
| 3.0.1 | 450 | 7/26/2026 |
| 3.0.0 | 552 | 7/20/2026 |
| 2.0.1 | 342 | 7/14/2026 |
| 2.0.0 | 158 | 7/14/2026 |
| 1.0.15 | 286 | 7/9/2026 |
| 1.0.14 | 328 | 7/8/2026 |
| 1.0.13 | 539 | 7/5/2026 |
| 1.0.2 | 309 | 6/12/2026 |