A follow-up question came in related to the last post, around how to add XData to entities using .NET.
Extended Entity Data (XData) is a legacy mechanism to attach additional information to AutoCAD entities. I say "legacy" as there are limits inherent to using XData, which make other mechanisms more appropriate when storing significant amounts of data. The global XData limit is 16 KBytes per object, and this potentially needs to be shared between multiple applications.
With AutoCAD 2007 came the complete switch to Unicode for string representation, which increases the storage requirements for strings in XData. Internally, the limit has increased to cope with this, but because of round-tripping requirements with older versions no more XData should be stored than the previously recommended limit.
XData is still popular for a number of reasons - it's simple to code against and is quite efficient for small amounts of data - but for any significant usage the preferred mechanism is to store XRecords in each object's Extension Dictionary, as demonstrated in this previous post. It's also possible to expose your own custom data objects from ObjectARX (C++) to .NET with a Managed Wrapper, but that's a much more advanced topic.
I've written some C# code that implements two commands - one to attach some XData to an entity chosen by the user (SXD), and the other to access and dump the XData attached to a selected entity to the command-line (GXD).
Here it is:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace ExtendedEntityData
{
public class Commands
{
[CommandMethod("GXD")]
static public void GetXData()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Ask the user to select an entity
// for which to retrieve XData
PromptEntityOptions opt =
new PromptEntityOptions(
"\nSelect entity: "
);
PromptEntityResult res =
ed.GetEntity(opt);
if (res.Status == PromptStatus.OK)
{
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
DBObject obj =
tr.GetObject(
res.ObjectId,
OpenMode.ForRead
);
ResultBuffer rb = obj.XData;
if (rb == null)
{
ed.WriteMessage(
"\nEntity does not have XData attached."
);
}
else
{
int n = 0;
foreach (TypedValue tv in rb)
{
ed.WriteMessage(
"\nTypedValue {0} - type: {1}, value: {2}",
n++,
tv.TypeCode,
tv.Value
);
}
rb.Dispose();
}
}
}
}
[CommandMethod("SXD")]
static public void SetXData()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Ask the user to select an entity
// for which to set XData
PromptEntityOptions opt =
new PromptEntityOptions(
"\nSelect entity: "
);
PromptEntityResult res =
ed.GetEntity(opt);
if (res.Status == PromptStatus.OK)
{
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
DBObject obj =
tr.GetObject(
res.ObjectId,
OpenMode.ForWrite
);
AddRegAppTableRecord("KEAN");
ResultBuffer rb =
new ResultBuffer(
new TypedValue(1001, "KEAN"),
new TypedValue(1000, "This is a test string")
);
obj.XData = rb;
rb.Dispose();
tr.Commit();
}
}
}
static void AddRegAppTableRecord(string regAppName)
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
RegAppTable rat =
(RegAppTable)tr.GetObject(
db.RegAppTableId,
OpenMode.ForRead,
false
);
if (!rat.Has(regAppName))
{
rat.UpgradeOpen();
RegAppTableRecord ratr =
new RegAppTableRecord();
ratr.Name = regAppName;
rat.Add(ratr);
tr.AddNewlyCreatedDBObject(ratr, true);
}
tr.Commit();
}
}
}
}
One point to note is the need to add a Registered Application to the appropriate table inside the drawing. The name you use for this should be prefixed with your Registered Developer Symbol (RDS), to prevent conflicts with other applications.
Out first weekend in Beijing was fine. We started gently, by sleeping late and making a trip to Wal-Mart, of all places! The Wal-Mart near to where we live in Beijing is - like all other Wal-Marts I've visited in the US - enormous. One very helpful thing for us was the labelling of all sections in both English and Mandarin. It was really a fun experience checking out the different produce and trying to work out what exactly we were buying!
A few key differences to Wal-Marts in the US:
- You can select your fish (and other fresh-/sea-water produce) from tanks - much as you can in restaurants in San Francisco's Chinatown (and presumably many restaurants in China, too :-).
- You can't take the trolley out of the store, whether getting into your own car or into a taxi. This posed quite a logistical challenge for us, as we had two kids (each with strollers) and had bought some bulk items to last us well into our 7-week stay. Ultimately I settled on leaving my wife and kids outside, while I made 3 trips up and down the escalators, ferrying shopping bags.
Oh, and I was also a little disappointed the store wasn't called "The Great Wal-Mart" (groan ;-)