Tracking entity handles through BEDIT

<?xml encoding=”UTF-8″>By Balaji Ramamoorthy

Entity handles in AutoCAD are unique within a database, but AutoCAD can still change them while still retaining them as unique. Block editing using BEDIT command is one such operation where you can expect the handle values to change. If your code is holding handle values of entities within a BlockTableRecord, you may be interested in tracking the handle values as they get changed during block editing.

Here is a sample code that monitors a few events to keep track of the handle values.

 <span>private</span><span>  <span>static</span><span>  String _blockName = <span>"Test"</span><span> ;</span></span></span>
 
 <span>private</span><span>  <span>static</span><span>  ObjectIdCollection _idsToMonitor </span></span>
 					= <span>new</span><span>  ObjectIdCollection();</span>
 
 <span>private</span><span>  <span>static</span><span>  Dictionary<<span>long</span><span> , <span>long</span><span> > _idMap </span></span></span></span>
 				= <span>new</span><span>  Dictionary<<span>long</span><span> , <span>long</span><span> >();</span></span></span>
 
 [CommandMethod(<span>"StartTracking"</span><span> )]</span>
 <span>public</span><span>  <span>void</span><span>  StartTracking()</span></span>
 <span>{</span>
     CreateBlockDef();
 
     Document activeDoc 
 		= Application.DocumentManager.MdiActiveDocument;
 
     activeDoc.CommandWillStart 
 		+=<span>new</span><span>  CommandEventHandler(activeDoc_CommandWillStart);</span>
 
     activeDoc.CommandEnded 
 		+=<span>new</span><span>  CommandEventHandler(activeDoc_CommandEnded);</span>
 
     Database db = activeDoc.Database;
     
 	db.BeginDeepCloneTranslation 
 	+= <span>new</span><span>  IdMappingEventHandler(db_BeginDeepCloneTranslation);</span>
     
 	db.ObjectErased 
 		+= <span>new</span><span>  ObjectErasedEventHandler(db_ObjectErased);</span>
 <span>}</span>
 
 <span>void</span><span>  activeDoc_CommandEnded(object sender, CommandEventArgs e)</span>
 <span>{</span>
     String cmdName = e.GlobalCommandName;
     <span>if</span><span> (cmdName.Equals(<span>"BCLOSE"</span><span> ))</span></span>
     <span>{</span>
         Document activeDoc 
 			= Application.DocumentManager.MdiActiveDocument;
         Database db = activeDoc.Database;
         <span>// Check if the ObjectId exist</span><span> </span>
         <span>int</span><span>  i = 0;</span>
         foreach (ObjectId id in _idsToMonitor)
         <span>{</span>
             <span>bool</span><span>  findReplacement </span>
 				= id.IsErased || id.IsEffectivelyErased;
 
             <span>if</span><span> (findReplacement)</span>
             <span>{</span> <span>// Has changed. Find the new one.</span><span> </span>
                 <span>if</span><span>  (_idMap.ContainsKey(id.Handle.Value))</span>
                 <span>{</span>
                     Handle newHandle 
 						= <span>new</span><span>  Handle(_idMap[id.Handle.Value]);</span>
 
                     ObjectId newId = ObjectId.Null;
                     <span>if</span><span>  (db.TryGetObjectId(newHandle, </span>
 										out newId))
                     <span>{</span>
                         <span>// New Id Exists</span><span> </span>
                         _idsToMonitor[i] = newId;
 
                         activeDoc.Editor.WriteMessage(
 
                         String.Format(
 						<span>"<span>{</span>0<span>}</span> <span>{</span>1<span>}</span> mapped to <span>{</span>2<span>}</span> <span>{</span>3<span>}</span>"</span><span> , </span>
                         Environment.NewLine, 
                         id.Handle, 
                         newId.Handle, 
                         (newId.IsEffectivelyErased 
 						|| newId.IsErased) ?
                         <span>"Erased"</span><span>  : String.Empty)</span>
 						
 						);
                     <span>}</span>
                     <span>else</span><span> </span>
                     <span>{</span>
                         <span>// Cannot determine the new handle !!</span><span> </span>
                         activeDoc.Editor.WriteMessage(
                         <span>"Sorry, Cannot find the new handle !!"</span><span> );</span>
                     <span>}</span>
                 <span>}</span>
                 <span>else</span><span> </span>
                 <span>{</span> 
                     <span>// Cannot determine the new handle !!</span><span> </span>
                     activeDoc.Editor.WriteMessage(
                     <span>"Sorry, Cannot find the new handle !!"</span><span> );</span>
                 <span>}</span>
             <span>}</span>
             i++;
         <span>}</span>
 
         <span>// New set of ids to monitor</span><span> </span>
         _idsToMonitor.Clear();
         <span>using</span><span>  (Transaction tr </span>
 			= db.TransactionManager.StartTransaction())
         <span>{</span>
             BlockTable bt 
 				= tr.GetObject(db.BlockTableId, OpenMode.ForRead)
 				as BlockTable;
 
             <span>if</span><span>  (bt.Has(_blockName))</span>
             <span>{</span>
                 BlockTableRecord btr 
 				= tr.GetObject(bt[_blockName], OpenMode.ForRead)
 				as BlockTableRecord;
 
                 foreach (ObjectId id in btr)
                 <span>{</span>
                     _idsToMonitor.Add(id);
                 <span>}</span>
             <span>}</span>
             tr.Commit();
         <span>}</span>
     <span>}</span>
 <span>}</span>
 
 <span>void</span><span>  activeDoc_CommandWillStart(</span>
 	object sender, CommandEventArgs e)
 <span>{</span>
     String cmdName = e.GlobalCommandName;
     <span>if</span><span>  (cmdName.Equals(<span>"BEDIT"</span><span> ))</span></span>
     <span>{</span>
         _idMap.Clear();
     <span>}</span>
 <span>}</span>
 
 [CommandMethod(<span>"EndTracking"</span><span> )]</span>
 <span>public</span><span>  <span>void</span><span>  EndTracking()</span></span>
 <span>{</span>
     Database db 
 		= Application.DocumentManager.MdiActiveDocument.Database;
 
     db.BeginDeepCloneTranslation 
 		-= <span>new</span><span>  IdMappingEventHandler(db_BeginDeepCloneTranslation);</span>
 
     db.ObjectErased 
 		-= <span>new</span><span>  ObjectErasedEventHandler(db_ObjectErased);</span>
 <span>}</span>
 
 <span>static</span><span>  <span>void</span><span>  db_BeginDeepCloneTranslation(</span></span>
 				object sender, IdMappingEventArgs e)
 <span>{</span>
     foreach (ObjectId id in _idsToMonitor)
     <span>{</span>
         <span>if</span><span>  (e.IdMapping.Contains(id))</span>
         <span>{</span>
             Editor ed 
 			= Application.DocumentManager.MdiActiveDocument.Editor;
 
             IdPair idPair = e.IdMapping[id];
             _idMap.Add(
 				idPair.Key.Handle.Value, 
 				idPair.Value.Handle.Value);
 
             ed.WriteMessage(
 				String.Format(<span>"<span>{</span>0<span>}</span> <span>{</span>1<span>}</span> mapped to <span>{</span>2<span>}</span>"</span><span> , </span>
 				Environment.NewLine, 
 				idPair.Key.Handle, 
 				idPair.Value.Handle));
         <span>}</span>
     <span>}</span>
 <span>}</span>
 
 <span>void</span><span>  db_ObjectErased(object sender, ObjectErasedEventArgs e)</span>
 <span>{</span>
     foreach (ObjectId id in _idsToMonitor)
     <span>{</span>
         <span>if</span><span>  (e.DBObject.ObjectId.Equals(id))</span>
         <span>{</span>
             Editor ed 
 			= Application.DocumentManager.MdiActiveDocument.Editor;
 
             ed.WriteMessage(String.Format(<span>"<span>{</span>0<span>}</span> <span>{</span>1<span>}</span> erased"</span><span> , </span>
 				Environment.NewLine, id.Handle));
         <span>}</span>
     <span>}</span>
 
     foreach(KeyValuePair<<span>long</span><span> , <span>long</span><span> > kvp in _idMap)</span></span>
     <span>{</span>
         <span>if</span><span> (e.DBObject.ObjectId.Handle.Value.Equals(kvp.Value))</span>
         <span>{</span>
             Editor ed 
 				= Application.DocumentManager.MdiActiveDocument.Editor;
 
             ed.WriteMessage(String.Format(<span>"<span>{</span>0<span>}</span> <span>{</span>1<span>}</span> erased"</span><span> , </span>
 				Environment.NewLine, kvp.Value.ToString(<span>"X"</span><span> )));</span>
         <span>}</span>
     <span>}</span>
 <span>}</span>
 
 <span>public</span><span>  <span>static</span><span>  <span>void</span><span>  CreateBlockDef()</span></span></span>
 <span>{</span>
     Document activeDoc 
 		= Application.DocumentManager.MdiActiveDocument;
     Database db = activeDoc.Database;
     Editor ed 
 	= Application.DocumentManager.MdiActiveDocument.Editor;
 
     _idsToMonitor.Clear();
 
     <span>using</span><span>  (Transaction tr </span>
 		= db.TransactionManager.StartTransaction())
     <span>{</span>
         BlockTable bt = tr.GetObject(
 			db.BlockTableId, OpenMode.ForRead) as BlockTable;
 
         <span>if</span><span>  (bt.Has(_blockName) == <span>false</span><span> )</span></span>
         <span>{</span>
             bt.UpgradeOpen();
             BlockTableRecord btr = <span>new</span><span>  BlockTableRecord();</span>
             btr.Name = _blockName;
             btr.Origin = Point3d.Origin;
             bt.Add(btr);
             tr.AddNewlyCreatedDBObject(btr, <span>true</span><span> );</span>
 
             ObjectId id = ObjectId.Null;
 
             Circle c1 = <span>new</span><span>  Circle(</span>
 				Point3d.Origin, 
 				Vector3d.ZAxis, 1.0);
 
             id = btr.AppendEntity(c1);
             _idsToMonitor.Add(id);
             tr.AddNewlyCreatedDBObject(c1, <span>true</span><span> );</span>
 
             Circle c2 = <span>new</span><span>  Circle(</span>
 				Point3d.Origin, 
 				Vector3d.ZAxis, 2.0);
 
             id = btr.AppendEntity(c2);
             _idsToMonitor.Add(id);
             tr.AddNewlyCreatedDBObject(c2, <span>true</span><span> );</span>
         <span>}</span>
 		<span>else</span><span> </span>
 		<span>{</span>
 			BlockTableRecord btr 
 				= tr.GetObject(bt[_blockName], OpenMode.ForRead)
 				as BlockTableRecord;
 
             foreach (ObjectId id in btr)
             <span>{</span>
                 _idsToMonitor.Add(id);
             <span>}</span>
 		<span>}</span>
 
         tr.Commit();
     <span>}</span>
 <span>}</span>
 

To try this code, open a new drawing in AutoCAD and run “StartTracking” command. Now “BEDIT” the newly created “Test” block. Watch out for messages in the command line to track the entity handles. Here is a sample output in the command line during my test, although the actual handle values can vary in your case.

1


Comments

3 responses to “Tracking entity handles through BEDIT”

  1. This is interesting I thought that handles never changed and they were “safe” to use when tracking objects between the file being open.
    So if you had an app tracking handles and tried to do a sync between known handles and what is existing in the drawing you could end up thinking that they are deleted when really they have just been bedit’ed?
    I am guessing I know the answer to this already but there is no mechanism in the API to track an object/entity definitely without condition between drawing open/close?

  2. Hi Dru,
    I am not aware of any other built-in mechanism to track it.
    You can try using DBObject events, but I wanted to only track the changes during the BEDIT operation.
    The reason for that being, BEDIT is the only operation that i know which changes the handle, so it may not be worth to have DBObject events subscribed all the time.
    Regards,
    Balaji

  3. Hi Balaji,
    This is interesting , but in Autodesk AdvanceSteel For every command Seperate COM process starts and that modifies many Objects togather .So this Code hangs when we close those Joint Box (COM interfaces)
    What Precautions should we take
    When Model Browser is opened this mechanism hangs and Model Browser Goes to Not Responding State
    Regards
    Sanjoy

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading