BRX.NET: erasing entities

Hello all,

I've been playing around with the .NET wrappers (speedy stuff!)  and I'm running into following:
Code snippet below selects a number of entities in an ObjectIdCollection by using a SelectionSet and some filters.
What I want to do is erase those objects but obviously they reside in some kind of block. (Modelspace, Paperspace, any block) 
Just passing those id's to an 'erase' loop does not seem to do the trick, I think I need to open one or more BlockTableRecords for 'write' to do the job?
Any comments?

TIA
Arno van Eeuwen
[code]public static bool EraseEntities(short[] filterType, object[] filterData)
    {      _AcAp.Document document = _AcAp.Application.DocumentManager.MdiActiveDocument;      _AcEd.Editor editor = document.Editor;      _AcDb.Database database = document.Database;            ObjectIdCollection ids;       try      {        using (_AcDb.Transaction trans = database.TransactionManager.StartTransaction())        {          ids = GetSelectionIds(filterType, filterData);           foreach (ObjectId id in ids)          {            DBObject entity = (DBObject)trans.GetObject(id, OpenMode.ForWrite);            entity.Erase();          }          trans.Commit();        }        database.ReclaimMemoryFromErasedObjects(ids);        return true;      }      catch (System.Exception ex)      {        _AcAp.Application.ShowAlertDialog(string.Format("\nError: {0}\nStackTrace: {1}", ex.Message, ex.StackTrace));        return false;      }     
    }[/code]

Comments

  • Hi Arno,

    looks like you may have found a bug! It took me a while to find where it was hiding, but I found it.

    it's in the constructor public ObjectIdCollection(ObjectId[] values);

    to work around it, build your ObjectIdCollection using add I.e.

     

    [code]

    static _AcDb.ObjectIdCollection ToObjectIdCollection(IEnumerable<<span style="color: #010001;">_AcDb.ObjectId> ids)

        {

          _AcDb.ObjectIdCollection col = new _AcDb.ObjectIdCollection();

          foreach (_AcDb.ObjectId id in ids)

            col.Add(id);

          return col;

        }

    [/code]

     

    here is the test I used

    [code]

    namespace BcadMgdTest

    {

      public static class Commands

      {

        [_AcRx.CommandMethod("doit")]

        public static void doit()

        {

          List<<span style="color: #010001;">_AcDb.ObjectId> ids = new List<<span style="color: #010001;">_AcDb.ObjectId>();

          _AcAp.Document doc = _AcAp.Application.DocumentManager.MdiActiveDocument;

          _AcEd.Editor ed = doc.Editor;

          _AcDb.Database db = doc.Database;

          _AcDb.TransactionManager tm = db.TransactionManager;

          using (_AcDb.Transaction tr = tm.StartTransaction())

          {

           _AcDb.BlockTable blockTable = tr.GetObject

              (db.BlockTableId, _AcDb.OpenMode.ForRead, false)

                 as _AcDb.BlockTable;

            foreach (_AcDb.ObjectId blockTableRecordId in blockTable)

            {

              _AcDb.BlockTableRecord blockTableRecord = tr.GetObject

                (blockTableRecordId, _AcDb.OpenMode.ForRead, false)

                   as _AcDb.BlockTableRecord;

              foreach (_AcDb.ObjectId id in blockTableRecord)

              {

                ids.Add(id);

              }

            }

            tr.Commit();

          }

          testids(ids, doc);

          testids(ToObjectIdCollection(ids), doc);

          // bug in ObjectIdCollection ctor

          testids(new _AcDb.ObjectIdCollection(ids.ToArray()), doc);

        }

     

        static _AcDb.ObjectIdCollection ToObjectIdCollection(IEnumerable<<span style="color: #010001;">_AcDb.ObjectId> ids)

        {

          _AcDb.ObjectIdCollection col = new _AcDb.ObjectIdCollection();

          foreach (_AcDb.ObjectId id in ids)

            col.Add(id);

          return col;

        }

     

        public static void testids(IEnumerable<<span style="color: #010001;">_AcDb.ObjectId> ids, _AcAp.Document document)

        {

          document.Editor.WriteMessage("\nstart\n");

          foreach (_AcDb.ObjectId id in ids)

            document.Editor.WriteMessage("-{0}-", id);

          document.Editor.WriteMessage("\nend\n");

        }

     

        public static void testids(_AcDb.ObjectIdCollection ids, _AcAp.Document document)

        {

          document.Editor.WriteMessage("\nstart\n");

          foreach (_AcDb.ObjectId id in ids)

            document.Editor.WriteMessage("-{0}-", id);

          document.Editor.WriteMessage("\nend\n");

        }

      }

    }

    [/code] 

    I will file a report on this so it's fixed.

  • Spot on Dan!

    That's exatly what I saw; the first id in the collection is found, the second one was '0' causing the problems.

    I do use the ObjectCollectionIds(ObjectIds[] values) to wrap the selected entity IDs but that was in the GetSelectionIds method I didn't send. ;-)

    Another mistery solved hopefully.

    Cheers,

    Arno

  • Hi Arno,

     

    Instead of using static methods to convert collections. have a look at using oop and .NET's implicit operators. Unfortunately, the wrappers use non generic collections that limit the use of all the cool goodies, such as lambda expressions. to solve this you can use something like this

    [code]

      public class ObjectIdList : List<<span style="color: #2b91af;">ObjectId>

      {

        public ObjectIdList(){}

        public ObjectIdList(ObjectId src)

        {

          base.Add(src);

        }

        public ObjectIdList(ObjectId[] src)

        {

          base.AddRange(src);

        }

        public ObjectIdList(ObjectIdList src)

        {

          base.AddRange(src);

        }

        public ObjectIdList(ObjectIdCollection src)

        {

          foreach (ObjectId oid in src)

            base.Add(oid);

        }

        public static implicit operator ObjectIdList(ObjectId[] src)

        {

          return ((src != null) ? new ObjectIdList(src) : null);

        }

        public static implicit operator ObjectIdList(ObjectIdCollection src)

        {

          return ((src != null) ? new ObjectIdList(src) : null);

        }

        public static implicit operator ObjectId[](ObjectIdList src)

        {

          return ((src != null) ? src.ToArray() : null);

        }

        public static implicit operator ObjectIdCollection(ObjectIdList src)

        {

          ObjectIdCollection dest = new ObjectIdCollection();

          src.ForEach(Item => dest.Add(Item));

          return dest;

        }

      }

    [/code]

    the class can then be used as

    [code]

      public static class Commands

      {

        [_AcRx.CommandMethod("doit")]

        public static void doit()

        {

          _AcAp.Document doc = _AcAp.Application.DocumentManager.MdiActiveDocument;

          _AcEd.PromptSelectionResult res = doc.Editor.GetSelection();

          if (res.Status == _AcEd.PromptStatus.OK)

          {

            ObjectIdList ids = res.Value.GetObjectIds();

            testids(ids, doc);

          }

        }

     

        public static void testids(ObjectIdList ids, _AcAp.Document document)

        {

     

          //lambda expresion

          ids.ForEach( ID => document.Editor.WriteMessage("-{0}-", ID));

     

          // implicit cast to ObjectIdCollection;

          document.Database.ReclaimMemoryFromErasedObjects(ids);

        }

      }

    [/code]

    cheers : )

  • Also.. There is a TypedValueList class somewhere at the swamp that wraps  Resulbuffer + TypedValue[]  very useful for creating selection set filters : )

  • Thanks a lot Daniel, this will keep me going for a while...

  •  Just to complete this subject for those interested: I had left out the GetSelectionIds() method just because it didn't seem to matter, but that's where the problem was. Here's the snippets I was playing with  (see the fix at the end of the try block):

    [code]public static ObjectIdCollection GetSelectionIds (short[] filterType, object[] filterData)
        {      _AcEd.Editor editor = _AcAp.Application.DocumentManager.MdiActiveDocument.Editor;       ObjectIdCollection ids = new ObjectIdCollection();       try      {        List<_AcDb.</font>TypedValue> dxfCodes = new List<</font>TypedValue>(filterType.Length);         for (int i = 0; i < filterType.Length; i++)          dxfCodes.Add(</font>new _AcDb.TypedValue(filterType[i], filterData[i]));         _AcEd.SelectionFilter selectionFilter = new SelectionFilter(dxfCodes.ToArray());         _AcEd.PromptSelectionResult res = editor.SelectAll(selectionFilter);         if (res.Status == _AcEd.PromptStatus.OK)        {          _AcEd.SelectionSet sset = res.Value;                   //ids =  new ObjectIdCollection(sset.GetObjectIds()); << //this was causing the problem</span>          foreach (ObjectId objectId in sset.GetObjectIds())       //the fix as suggested by Daniel            ids.Add(objectId);        }      }      catch (System.Exception ex)      {        _AcAp.Application.ShowAlertDialog(string.Format("\nError: {0}\nStackTrace: {1}", ex.Message, ex.StackTrace));           }      return ids;      
        }[/code]
This discussion has been closed.