Handbook
Handbook
Handbook
CP2146 This class is about working with the Named Object Dictionary (NOD) and other
dictionaries that can exist in an AutoCAD® software drawing database using .NET applications. We will
look at getting and using dictionary keys such as get/add an UnderlayDefinition key for adding DGN,
DWF™ and PDF file underlay references to the active document. The Named Object Dictionary can
contain other dictionaries like the ACAD_MLINESTYLE and ACAD_MATERIAL dictionaries, of which we
will have code samples to show you how to use the data in those and other drawing database
dictionaries. You will leave this class with a good understanding and with code samples for working with
AutoCAD drawing database dictionaries and know what is typically stored in the Named Object
Dictionary.
Learning
Objectives
At the end of this class, you will be able to:
• Describe what the Named Object Dictionary contains and how to work with those dictionary keys
• Add and get underlay definitions in the Named Object Dictionary
• Work with drawing database dictionaries in a .NET application
• Use XRecords in dictionaries to store application information within a drawing
Email: james.e.johnson@me.com
Using .NET in the Land of NOD
AutoCAD® dictionaries...
In an AutoCAD® drawing database a dictionary is a container object which can contain any AutoCAD®
object or an XRecord.
Dictionaries are stored either in the database under the named object dictionary or as an extension
dictionary of a table record or graphical entity. The named object dictionary is the master table for all of
the dictionaries associated with a database. Unlike symbol tables, new dictionaries can be created and
added to the named object dictionary.
Describe what the Named Object Dictionary contains and how to work with those
dictionary keys...
The Named Object Dictionary contains all dictionaries other than extension dictionaries in the drawing
database. Dictionary objects cannot contain drawing entities.
The Named Object Dictionary is where data is placed for the entire drawing to access. This dictionary is
always present in all drawing databases. AutoCAD® uses this dictionary for items such as Material styles
and MLine styles.
An Extension dictionary is a dictionary that is attached to an entity to store Objects/XRecords which are
typically entity specific.
ACAD_CIP_PREVIOUS_PRODUCT_INFO
ACAD_COLOR
ACAD_DETAILVIEWSTYLE In code the Dictionary
ACAD_GROUP entries are handled with the
ACAD_LAYOUT DBDictionaryEntry
class by
ACAD_MATERIAL enumerating through the
ACAD_MLEADERSTYLE contents of a dictionary...
ACAD_MLINESTYLE
ACAD_PLOTSETTINGS
ACAD_PLOTSTYLENAME
ACAD_SCALELIST
ACAD_SECTIONVIEWSTYLE
ACAD_TABLESTYLE
ACAD_VISUALSTYLE
AcDbVariableDictionary
The dictionary is accessed in .NET as an AutoCAD DBDictionary object. To get an instance from the
active drawing database:
2
Using .NET in the Land of NOD
[CommandMethod("GetNOD")]
public
void
getNOD()
{
Editor
ed
=
Application.DocumentManager
.MdiActiveDocument
.Editor;
The Named Object dictionary can also be accessed at the AutoCAD Command
line with AutoLISP:
Returns:
((-‐1
.
<Entity
name:
7ffff7038c0>)
(0
.
"DICTIONARY")
(330
.
<Entity
name:
0>)
(5
.
"C")
(100
.
"AcDbDictionary")
(280
.
0)
(281
.
1)
(3
.
"ACAD_CIP_PREVIOUS_PRODUCT_INFO")
(350
.
<Entity
name:
7ffff705ad0>)
(3
.
"ACAD_COLOR")
(350
.
<Entity
name:
7ffff703c30>)
(3
.
"ACAD_DETAILVIEWSTYLE")
(350
.
<Entity
name:
7ffff705b30>)
(3
.
"ACAD_GROUP")
(350
.
<Entity
name:
7ffff7038d0>)
(3
.
"ACAD_LAYOUT")
(350
.
<Entity
name:
7ffff7039a0>)
(3
.
"ACAD_MATERIAL")
(350
.
<Entity
name:
7ffff703c20>)
(3
.
"ACAD_MLEADERSTYLE")
(350
.
<Entity
name:
7ffff7050f0>)
(3
.
"ACAD_MLINESTYLE")
(350
.
<Entity
name:
7ffff703970>)
(3
.
"ACAD_PLOTSETTINGS")
(350
.
<Entity
name:
7ffff703990>)
(3
.
"ACAD_PLOTSTYLENAME")
(350
.
<Entity
name:
7ffff7038e0>)
(3
.
"ACAD_SCALELIST")
(350
.
<Entity
name:
7ffff705060>)
(3
.
"ACAD_SECTIONVIEWSTYLE")
(350
.
<Entity
name:
7ffff705b00>)
(3
.
"ACAD_TABLESTYLE")
(350
.
<Entity
name:
7ffff703ce0>)
(3
.
"ACAD_VISUALSTYLE")
(350
.
<Entity
name:
7ffff703e10>)
(3
.
"AcDbVariableDictionary")
(350
.
<Entity
name:
7ffff703b60>))
3
Using .NET in the Land of NOD
[CommandMethod("addToNOD")]
public
void
addToNOD()
{
Editor
ed
=
Application.DocumentManager
.MdiActiveDocument
.Editor;
using
(Transaction
tr
=
HostApplicationServices
.WorkingDatabase
.TransactionManager
.StartTransaction())
{
DBDictionary
nod
=
tr.GetObject(HostApplicationServices
.WorkingDatabase
.NamedObjectsDictionaryId,
OpenMode.ForWrite)
as
DBDictionary;
string
newDictName
=
"LandOfNod";
DBDictionary
newDict
=
new
DBDictionary();
if
(!nod.Contains(newDictName))
{
nod.SetAt(newDictName,
newDict); Creates a new DBDictionary
tr.AddNewlyCreatedDBObject(newDict,
true); and adds it to the database...
}
tr.Commit();
}
}
[CommandMethod("removeNOD")]
public
void
removeNOD()
{
Editor
ed
=
Application.DocumentManager
.MdiActiveDocument
.Editor;
using
(Transaction
tr
=
HostApplicationServices
.WorkingDatabase
.TransactionManager
.StartTransaction())
{
DBDictionary
nod
=
tr.GetObject(HostApplicationServices
.WorkingDatabase
.NamedObjectsDictionaryId,
OpenMode.ForWrite)
as
DBDictionary;
string
newDictName
=
"LandOfNod";
DBDictionary
newDict
=
new
DBDictionary();
if
(nod.Contains(newDictName))
{ Removes the DBDictionary
nod.Remove(newDictName);
and all of its contents from the
} database...
tr.Commit();
}
}
4
Using .NET in the Land of NOD
The following example illustrates getting an ObjectID of a dictionary entry in the NOD then iterates
through that dictionary. In this example the “ACAD_LAYOUT” name is used to get the proper dictionary
entry then the value (ObjectID) is used to open the dictionary. This could have also been accomplished
using the layout dictionary ID from the database:
HostApplicationServices.WorkingDatabase.LayoutDictionaryId
Other
Default
dictionaries
can
be
acquired
in
the
same
way:
HostApplicationServices.WorkingDatabase.MaterialDictionaryId
HostApplicationServices.WorkingDatabase.MLeaderStyleDictionaryId
HostApplicationServices.WorkingDatabase.MLStyleDictionaryId
HostApplicationServices.WorkingDatabase.ColorDictionaryId
[CommandMethod("GetNODLayout")]
public
void
getNODLayout()
{
Editor
ed
=
Application.DocumentManager
.MdiActiveDocument
.Editor;
if
(nod.Contains("ACAD_LAYOUT"))
{
foreach
(DBDictionaryEntry
de
in
nod)
{
if
(de.Key
==
"ACAD_LAYOUT")
{
DBDictionary
layoutDB
=
(DBDictionary)tr.GetObject(
de.Value,
OpenMode.ForRead);
5
Using .NET in the Land of NOD
The UnderlayReference object is responsible for the placement of the content within the drawing, while
the UnderlayDefinition object handles the linkage to the underlay content.
There are three primary classes that Inherit from the UnderlayDefinition class, Instances of
UnderlayDefinition-derived concrete classes are inserted into a dictionary within the named object
dictionary...
Autodesk.AutoCAD.DatabaseServices.UnderlayDefinition
Autodesk.AutoCAD.DatabaseServices.DgnDefinition
Autodesk.AutoCAD.DatabaseServices.DwfDefinition
Autodesk.AutoCAD.DatabaseServices.PdfDefinition
There are three primary classes that Inherit from the UnderlayReference class, Instances of
UnderlayReference-derived concrete classes are inserted into a block table record...
Autodesk.AutoCAD.DatabaseServices.UnderlayReference
Autodesk.AutoCAD.DatabaseServices.DgnReference
Autodesk.AutoCAD.DatabaseServices.DwfReference
Autodesk.AutoCAD.DatabaseServices.PdfReference
When an UnderlayDefinition is added to the drawing the associated dictionaries are added to the named
object dictionary...
Dictionary added
for DWF underlay,
Dictionary added
for PDF underlay,
6
Using .NET in the Land of NOD
[CommandMethod("pdfInsert")]
static
public
void
pdfInsert()
{
Document
doc
=
Application.DocumentManager.MdiActiveDocument;
Database
db
=
doc.Database;
if
(!nod.Contains(defPDFDictKey))
{
using
(DBDictionary
dict
=
new
DBDictionary())
{
nod.SetAt(defPDFDictKey,
dict);
tr.AddNewlyCreatedDBObject(dict,
true);
}
}
ObjectId
defObjID;
DBDictionary
pdfDict
=
(DBDictionary)tr
.GetObject(nod.GetAt(defPDFDictKey),
OpenMode.ForWrite);
tr.Commit();
}
}
7
Using .NET in the Land of NOD
[CommandMethod("dwfInsert")]
static
public
void
dwfInsert()
{
Document
doc
=
Application.DocumentManager.MdiActiveDocument;
Database
db
=
doc.Database;
if
(!nod.Contains(defDWFDictKey))
{
using
(DBDictionary
dict
=
new
DBDictionary())
{
nod.SetAt(defDWFDictKey,
dict);
tr.AddNewlyCreatedDBObject(dict,
true);
}
}
ObjectId
defObjID;
DBDictionary
dwfDict
=
(DBDictionary)tr
.GetObject(nod.GetAt(defDWFDictKey),
OpenMode.ForWrite);
tr.Commit();
}
}
8
Using .NET in the Land of NOD
[CommandMethod("pdfSearch")]
static
public
void
pdfSearch()
{
Editor
ed
=
Application.DocumentManager
.MdiActiveDocument
.Editor;
if
(nod.Contains(defPDFDictKey))
{
foreach
(DBDictionaryEntry
de
in
nod)
{
try
{
if
(de.Key
==
defPDFDictKey)
{
DBDictionary
pdfDict
=
(DBDictionary)de.Value
.GetObject(OpenMode.ForRead);
foreach
(DBDictionaryEntry
pdfDE
in
pdfDict)
{
PdfDefinition
pdf
=
(PdfDefinition)pdfDE.Value
.GetObject(OpenMode.ForRead);
Steps through
string
pdfPath
=
pdf.SourceFileName;
dictionary looking
if
((pdf.ActiveFileName
!=
null)
&&
for PdfDefinition...
(pdf.ActiveFileName
!=
string.Empty))
{
pdfPath
=
pdf.ActiveFileName;
}
}
}
}
9
Using .NET in the Land of NOD
[CommandMethod("dwfSearch")]
static
public
void
dwfSearch()
{
Editor
ed
=
Application.DocumentManager
.MdiActiveDocument
.Editor;
if
(nod.Contains(defDWFDictKey))
{
foreach
(DBDictionaryEntry
de
in
nod)
{
try
{
if
(de.Key
==
defDWFDictKey)
{
DBDictionary
dwfDict
=
(DBDictionary)de.Value
.GetObject(OpenMode.ForRead);
foreach
(DBDictionaryEntry
dwfDE
in
dwfDict)
{
DwfDefinition
dwf
=
(DwfDefinition)dwfDE.Value
.GetObject(OpenMode.ForRead);
}
}
}
10
Using .NET in the Land of NOD
Objects added to a dictionary must have NULL handles and must not have a presence in the database.
When a dictionary is erased, all the objects within it are erased.
When a dictionary is unerased, all of its contents are unerased.
11
Using .NET in the Land of NOD
An XRecords structure for data input and output is done with a linked list of Resultbuffer structures, which
is a list of TypedValue items. TheTypedValue object pairs a DXF Code with its associated data.
12
Using .NET in the Land of NOD
13
Using .NET in the Land of NOD
[CommandMethod("addXRecordToEntity")]
public
void
addXRecord()
{
Document
doc
=
Application.DocumentManager.MdiActiveDocument;
Database
db
=
doc.Database;
Editor
ed
=
doc.Editor;
PromptEntityOptions
pEntOp
=
new
PromptEntityOptions("\nSelect
an
entity:
");
pEntOp.AllowNone
=
false;
PromptEntityResult
per
=
ed.GetEntity(pEntOp);
if
(per.Status
==
PromptStatus.OK)
{
ObjectId
id
=
per.ObjectId;
Creates a new ResultBuffer and
ResultBuffer
resbuf
=
new
ResultBuffer(
assigns some values...
new
TypedValue((int)DxfCode.Text,
"HELLO"),
new
TypedValue((int)DxfCode.Int16,
256),
new
TypedValue((int)DxfCode.Real,
25.4));
writeXRecord(id,
"hello",
resbuf);
}
}
14
Using .NET in the Land of NOD
The Dynamic Language Runtime (DLR) is used to implement dynamic languages like Python and Ruby
on the .NET Framework.
In Visual Studio 2010 C# a new type of 'dynamic' was introduced. This is a static type that bypasses static
type checking and functions like it has a type of object. A dynamic type at compile time assumes support
for any operation, whether its value comes from a COM API, a dynamic language, an HTML Document
Object Model (DOM), reflection, or somewhere in the program. Errors are caught at run time for invalid
code.
The equivalent to the dynamic keyword is object in VB.NET but with ‘Option Strict Off’, with ‘Option Strict
On’ there is no equivalent.
try
{
var
xr
=
nod[dictName][xRecName];
ed.WriteMessage("\n
-‐
"
+
xr.Data.ToString());
}
catch
(Autodesk.AutoCAD.Runtime.Exception
acadEx)
{
if
(acadEx.ErrorStatus
==
ErrorStatus.KeyNotFound)
ed.WriteMessage("\nDictionary
or
record
does
not
exist");
}
}
record.Data
=
rb;
}
15
Using .NET in the Land of NOD
[CommandMethod("addXRecordDynamic")]
public
void
addXRecordDynamic()
{
Document
doc
=
Application.DocumentManager.MdiActiveDocument;
Database
db
=
doc.Database;
Editor
ed
=
doc.Editor;
PromptEntityOptions
pEntOp
=
new
PromptEntityOptions("\nSelect
an
entity:
");
pEntOp.AllowNone
=
false;
PromptEntityResult
per
=
ed.GetEntity(pEntOp);
if
(per.Status
==
PromptStatus.OK)
{
dynamic
ent
=
per.ObjectId;
dynamicXRecordEntWrite(ent,
"hello",
"Hello");
}
}
[CommandMethod("getXRecordDynamic")]
public
void
getXRecordDynamic()
{
Document
doc
=
Application.DocumentManager.MdiActiveDocument;
Database
db
=
doc.Database;
Editor
ed
=
doc.Editor;
PromptEntityOptions
pEntOp
=
new
PromptEntityOptions("\nSelect
an
entity:
");
pEntOp.AllowNone
=
false;
PromptEntityResult
per
=
ed.GetEntity(pEntOp);
if
(per.Status
==
PromptStatus.OK)
{
dynamic
ent
=
per.ObjectId;
dynamic
xrec
=
dynamicXRecordEntRead(ent,
"hello");
if
(xrec
==
null)
ed.WriteMessage("\nNo
XRecord
found...");
else
{
ed.WriteMessage("\n
-‐
"
+
xrec.Data.ToString());
}
}
}
16