A blog for developers programming with Autodesk platforms, particularly AutoCAD and Forge. With a special focus on AR/VR and IoT.

May 07, 2010

Populating a tree view inside AutoCAD with sheet set data using .NET

A big thank you to Fenton Webb, from DevTech Americas, for providing the code which was the basis for this post. Thanks, Fents! :-)

Fenton sent a version of this code recently to an ADN member who was interested in duplicating the information shown in AutoCAD’s Sheet Set Manager inside a custom, palette-hosted tree-view dialog. Fenton’s version made use of WPF: I’ve dumbed it down a little to use WinForms, but may do a follow-up post using WPF (although the WPF TreeView doesn’t appear to support data-binding, so I may well decide not to bother).

I have made some other changes to Fenton’s code, and if there are any bugs they’re likely to be mine rather than his. I fleshed out some of the various item types, but as I haven’t yet been able to see them in action (I’m not even sure there was any real need to do so), they may need some further work or even stripping out.

Anyway, here’s the C# code. To make it work your project will need a reference to acsmcomponents18.tlb (or acsmcomponents17.tlb if using AutoCAD 2007-2009) as well as AcMgd.dll, AcDbMgd.dll and the standard .NET components that Visual Studio may be looking for when building the project.

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;

using acApp =

Autodesk.AutoCAD.ApplicationServices;

using ACSMCOMPONENTS18Lib;

using System.Windows.Forms;

using System;

namespace MyApplication

{

publicclassCommands

{

staticPaletteSet ps = null;

staticUserControl1 userControl = null;

[CommandMethod("SSTREE")]

publicvoid PopulateCustomSheetTree()

{

// Check the state of the paletteset

if (ps == null)

{

// Then create it

ps = newPaletteSet("Custom Sheet Tree");

userControl = newUserControl1();

ps.Add("MySheetView", userControl);

}

ps.Visible = true;

// Get the AutoCAD Editor

Editor ed =

acApp.Application.DocumentManager.MdiActiveDocument.Editor;

// Get the SheetSet Manager

AcSmSheetSetMgr mgr = newAcSmSheetSetMgr();

// Create a new SheetSet Database

AcSmDatabase db = newAcSmDatabase();

// Try and load a default DST file...

try

{

db =

mgr.OpenDatabase(

@"C:\Program Files\Autodesk\AutoCAD 2011\Sample\" +

@"Sheet Sets\Architectural\IRD Addition.dst",

true

);

}

catch (System.Exception ex)

{

ed.WriteMessage(ex.ToString());

return;

}

// Lock the db for processing

db.LockDb(db);

AcSmSheetSet ss = db.GetSheetSet();

// Create a root item in the TreeView,

// the name of the SheetSet

TreeNode root = newTreeNode(ss.GetName());

userControl.treeView1.Nodes.Add(root);

ProcessEnumerator(ss.GetSheetEnumerator(), root);

db.UnlockDb(db, true);

mgr.Close(db);

}

void ProcessEnumerator(IAcSmEnumComponent iter, TreeNode root)

{

IAcSmComponent item = iter.Next();

while (item != null)

{

string type = item.GetTypeName();

switch (type)

{

case"AcSmSubset":

try

{

AcSmSubset subset = (AcSmSubset)item;

string subName = subset.GetName();

if (!String.IsNullOrEmpty(subName))

{

TreeNode tn = AddTreeNode(root, subName);

IAcSmEnumComponent enumerator =

(IAcSmEnumComponent)subset.GetSheetEnumerator();

ProcessEnumerator(enumerator, tn);

}

}

catch { }

break;

case"AcSmSheet":

try

{

AcSmSheet sh = (AcSmSheet)item;

string shName = sh.GetName();

if (!String.IsNullOrEmpty(shName))

{

TreeNode tn = AddTreeNode(root, shName);

IAcSmEnumComponent enumerator =

(IAcSmEnumComponent)sh.GetSheetViews();

ProcessEnumerator(enumerator, tn);

}

}

catch { }

break;

case"AcSmSheetViews":

try

{

AcSmSheet sh = (AcSmSheet)item;

string shName = sh.GetName();

if (!String.IsNullOrEmpty(shName))

{

TreeNode tn = AddTreeNode(root, shName);

IAcSmEnumComponent enumerator =

(IAcSmEnumComponent)sh.GetSheetViews();

ProcessEnumerator(enumerator, tn);

}

}

catch { }

break;

case"AcSmSheetView":

try

{

AcSmSheetView sv = (AcSmSheetView)item;

string svName = sv.GetName();

if (!String.IsNullOrEmpty(svName))

AddTreeNode(root, svName);

}

catch { }

break;

case"AcSmCustomPropertyValue":

AcSmCustomPropertyValue pv =

(AcSmCustomPropertyValue)item;

AddTreeNode(

root,

"Custom property value: " + pv.GetValue().ToString()

);

break;

case"AcSmObjectReference":

AcSmObjectReference or =

(AcSmObjectReference)item;

AddTreeNode(

root,

"Object reference: " +

or.GetReferencedObject().GetTypeName()

);

break;

case"AcSmCustomPropertyBag":

try

{

AcSmCustomPropertyBag bag =

(AcSmCustomPropertyBag)item;

TreeNode tn = AddTreeNode(root, "Custom property bag");

IAcSmEnumComponent enumerator =

(IAcSmEnumComponent)bag.GetPropertyEnumerator();

ProcessEnumerator(enumerator, tn);

}

catch { }

break;

case"AcSmAcDbLayoutReference":

AcSmAcDbLayoutReference lr =

(AcSmAcDbLayoutReference)item;

AddTreeNode(

root,

"Layout reference: " + lr.GetName()

);

break;

case"AcSmFileReference":

AcSmFileReference fr = (AcSmFileReference)item;

AddTreeNode(

root,

"Layout reference: " + fr.GetFileName()

);

break;

case"AcSmAcDbViewReference":

AcSmAcDbViewReference vr = (AcSmAcDbViewReference)item;

AddTreeNode(

root,

"View reference: " + vr.GetName()

);

break;

case"AcSmResources":

try

{

AcSmResources res = (AcSmResources)item;

TreeNode tn = AddTreeNode(root, "Resources");

IAcSmEnumComponent enumerator =

(IAcSmEnumComponent)res.GetEnumerator();

ProcessEnumerator(enumerator, tn);

}

catch { }

break;

default:

Document doc =

acApp.Application.DocumentManager.MdiActiveDocument;

Editor ed = doc.Editor;

ed.WriteMessage("\nMissed Type = " + type);

break;

}

item = iter.Next();

}

}

privateTreeNode AddTreeNode(TreeNode root, string name)

{

// Create a new node on the tree view

TreeNode node = newTreeNode(name);

// Add it to what we have

root.Nodes.Add(node);

return node;

}

}

}

You’ll need to add a new UserControl to your project and a TreeView to that, setting the Dock property to fill. Be sure to keep the default names as UserControl1 and treeView1. Other than than, no UI work is needed.

Here’s what happens when we run the SSTREE command along and load the hard-coded DST file into the SheetSet Manager (displayed with the SSM command) for comparison:

Clearly more could be done to make the UI look the same (icons, etc.), but this post is more about recursively parsing a SheetSet’s tree rather than anything else. If you come across any issues as you try this out with other data stored in DST files, be sure to post a comment.