Part of our process is to select lines to represent a zone. The tools should be able to prompt the user to select a line and change its color and assign it values such as a zone number.
What is the best way to add this data into the drawing for later use by the tool? Should I use Xdata on the objects? Or an Xrecord? Or add to the NOD?
I've heard of all of these things but I'm not clear on what the difference between them are, or how to do them
Hi,
You can use either xdata or xrecord in the extension dictionary of the entity.
Xdata is limited to a small amount of data per object (16 ko) and you need to share this small amount with all the other applications that use it.
Xrecords may be of arbitrary length and there may be many xrecords per entity.
Where would a resource be that explains how to do the whole XRecord process. I'm having a hard time finding one. I wish it was in the Developer Guide
Here're some extension methods.
public static class Extension
{
static class Assert
{
public static void IsNotNull<T>(T obj, string paramName) where T : class
{
if (obj == null)
throw new ArgumentNullException(paramName);
}
}
public static Transaction GetTopTransaction(this Database db)
{
Assert.IsNotNull(db, nameof(db));
return db.TransactionManager.TopTransaction ??
throw new AcRx.Exception(ErrorStatus.NoActiveTransactions);
}
public static DBDictionary TryGetExtensionDictionary(this DBObject source)
{
Assert.IsNotNull(source, nameof(source));
var tr = source.Database.GetTopTransaction();
ObjectId dictId = source.ExtensionDictionary;
if (dictId.IsNull)
{
return null;
}
return (DBDictionary)tr.GetObject(dictId, OpenMode.ForRead);
}
public static DBDictionary GetOrCreateExtensionDictionary(this DBObject source)
{
Assert.IsNotNull(source, nameof(source));
var tr = source.Database.GetTopTransaction();
if (source.ExtensionDictionary == ObjectId.Null)
{
source.UpgradeOpen();
source.CreateExtensionDictionary();
}
return (DBDictionary)tr.GetObject(source.ExtensionDictionary, OpenMode.ForRead);
}
public static ResultBuffer GetXrecordData(this DBObject source, string key)
{
Assert.IsNotNull(source, nameof(source));
var tr = source.Database.GetTopTransaction();
DBDictionary dict;
if (source is DBDictionary)
{
dict = (DBDictionary)source;
}
else
{
dict = source.TryGetExtensionDictionary();
if (dict == null)
return null;
}
if (!dict.Contains(key))
{
return null;
}
var xrec = tr.GetObject(dict.GetAt(key), OpenMode.ForRead) as Xrecord;
if (xrec == null)
{
return null;
}
return xrec.Data;
}
public static void SetXrecordData(this DBObject source, string key, ResultBuffer data)
{
Assert.IsNotNull(source, nameof(source));
var tr = source.Database.GetTopTransaction();
DBDictionary dict;
if (source is DBDictionary)
{
dict = (DBDictionary)source;
}
else
{
dict = source.GetOrCreateExtensionDictionary();
}
Xrecord xrec;
if (dict.Contains(key))
{
xrec = tr.GetObject(dict.GetAt(key), OpenMode.ForWrite) as Xrecord;
if (xrec == null)
{
throw new AcRx.Exception(ErrorStatus.InvalidKey, key);
}
}
else
{
dict.UpgradeOpen();
xrec = new Xrecord();
dict.SetAt(key, xrec);
tr.AddNewlyCreatedDBObject(xrec, true);
}
xrec.Data = data;
}
}
Thank you once again! This is really helpful. I do have a couple follow up questions.
I'm confused by creating a ResultBuffer(). When I see people do it it is usually in conjunction with TypedValue and in the legacy code I have there are Dxf Codes?
Also what do I do with a ResultBuffer once I have gotten it from GetXRecordData()?
The legacy code I have does really weird things with BinaryFormatter's and MemoryStreams?
Is there a simpler way?
A Resultbuffer is mainly a TypedValue collection. This is a convinient way to store data of various types.
A TypedValue is like a pair containing a TypeCode and a Value of corresponding type.
The TypedValue.TypeCode is a short which can also be expressed with enums as DxfCode (or LispDataType).
Can't find what you're looking for? Ask the community or share your knowledge.