Author Topic: Erase object by speficic layer  (Read 2275 times)

0 Members and 1 Guest are viewing this topic.

T.Willey

  • Needs a day job
  • Posts: 5251
Erase object by speficic layer
« on: December 17, 2017, 02:38:38 AM »
It has been a long time since I've written anything in C#, so I'm just posting this to see if there is some glaring mistake(s) I'm making.  The code works (I can provide the helper function that is called if desired) without errors, and I'm able to open the drawings that get saved afterwards without errors.

The only thing it is missing is, when a drawing is open in the editor the items are deleted, but the drawing is not refreshed.  Once clicking over to the drawing, then a regen clears the issue.

Thanks in advance.
Code - C#: [Select]
  1. public class EraseClouds
  2. {
  3.     [CommandMethod("EraseClouds", CommandFlags.Session)]
  4.     public void EraseCloud()
  5.     {
  6.         Autodesk.AutoCAD.Windows.OpenFileDialog dia = new Autodesk.AutoCAD.Windows.OpenFileDialog(
  7.             "Select drawings to erase could entities from.", "", "dwg", "tmwCloudErase",
  8.             Autodesk.AutoCAD.Windows.OpenFileDialog.OpenFileDialogFlags.AllowMultiple
  9.            );
  10.         if (dia.ShowDialog() != DialogResult.OK) return;
  11.         Document cdoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  12.         Database cdb = cdoc.Database;
  13.         string[] files = dia.GetFilenames();
  14.         Document doc;
  15.         DocumentLock dlock;
  16.         Database db;
  17.         BlockTable bt;
  18.         BlockTableRecord btr;
  19.         Entity ent;
  20.         LayerTable lt;
  21.         LayerTableRecord ltr;
  22.         bool didErase;
  23.         foreach (string name in files) {
  24.             didErase = false;
  25.             db = MyUtility.GetDatabaseAtPath(name, cdb, FileShare.Read, FindFileHint.XRefDrawing, out doc);
  26.             if (db == null) continue;
  27.             if (doc != null) dlock = doc.LockDocument();
  28.             using (Transaction trans = db.TransactionManager.StartTransaction()) {
  29.                 bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead, false, true) as BlockTable;
  30.                 foreach (ObjectId id in bt){
  31.                     btr = trans.GetObject(id, OpenMode.ForRead, false, true) as BlockTableRecord;
  32.                     foreach (ObjectId oid in btr){
  33.                         ent = trans.GetObject(oid, OpenMode.ForRead, false, true) as Entity;
  34.                         if (string.Compare(ent.Layer, 0, "Cloud-", 0, 6, true) == 0 ) {
  35.                             ent.UpgradeOpen();
  36.                             ent.Erase();
  37.                             ent.DowngradeOpen();
  38.                             didErase = true;
  39.                         }
  40.                     }
  41.                 }
  42.                 lt = trans.GetObject(db.LayerTableId, OpenMode.ForRead, false, true) as LayerTable;
  43.                 foreach (ObjectId id in lt){
  44.                     ltr = trans.GetObject(id, OpenMode.ForRead, false, true) as LayerTableRecord;
  45.                     if (string.Compare(ltr.Name, 0, "Cloud-", 0, 6, true) != 0) continue;
  46.                     ltr.UpgradeOpen();
  47.                     ltr.Erase();
  48.                     ltr.DowngradeOpen();
  49.                     didErase = true;
  50.                 }
  51.                 trans.Commit();
  52.             }
  53.             if (doc == null) {
  54.                 if (didErase){
  55.                     db.SaveAs(name, true, DwgVersion.Current, db.SecurityParameters);
  56.                     cdoc.Editor.WriteMessage("\n Erased cloud entities from: " + name);
  57.                 }
  58.                 db.Dispose(); // this is because of the helper function
  59.             }
  60.             else {
  61.                 if (didErase)
  62.                     cdoc.Editor.WriteMessage("\n Erase cloud entities from opened drawing: " + name);
  63.             }
  64.         }
  65.     }
  66. }
  67.  
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: Erase object by speficic layer
« Reply #1 on: December 17, 2017, 05:26:25 PM »
If just the regen is what you want, you could probably just throw a

Code - C#: [Select]
  1. cdoc.Editor.Regen();

in after the trans commit.

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Erase object by speficic layer
« Reply #2 on: December 17, 2017, 10:36:35 PM »
Code - C#: [Select]
  1. if (doc != null) dlock = doc.LockDocument();

You should put that in a "using" statement nested above the one for the transaction, mostly so it unlocks the doc when finished & disposes appropriately.

Code - C#: [Select]
  1. using (DocumentLock dlock = doc.LockDocument())
  2. using (Transaction trans = db.TransactionManager.StartTransaction()) {

yes, you can nest using statements like this, no need for nested braces if you wish to omit them.

n.yuan

  • Bull Frog
  • Posts: 348
Re: Erase object by speficic layer
« Reply #3 on: December 18, 2017, 10:15:37 AM »
When you say "... drawing is open in the editor..." do you mean after the process, you open the drawing in AutoCAD, or do you mean the drawing has opened in AutoCAD DUE TO the process, and the drawing shown/seen in the editor was not updated until you click the editor (natually, you can only do this to the last drawing that was process and left open)? It seems to me it is the latter case, but not very sure because of the rather strange method signature of

db = MyUtility.GetDatabaseAtPath([fileName], [CurrentMdiDoc], ...,... out [Document])

Does this fucntion is meant for returning a side database, of a database of currently opening document? The function's signature gives no hind which one it would return (or, maybe, if the out Doucment is null, then the returned database is side DB?). Judging by CommandFlags.Session, it seems the funxtion actually opens each drawing in the file name list in AutoCAD. If so, if would be better to let the function simply return the document, and its database can alsways accessed via Document.Database property

Now, if each drawing is opened in AutoCAD, each drawing, upon its opening in AutoCAD would become MdiActiveDocument due to CommandFlags.Session, you can simply call Editor.UpdateScreen() at the end of process to each drawing. You only need to call Editor.Regen() for certain changes to be seen, such as Field updated, Overrule applied...

It also seems to me that for the task your code performs could be done a lot faster with side database, instead of opening each in AutoCAD editor.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Erase object by speficic layer
« Reply #4 on: December 18, 2017, 11:39:28 AM »
Atook:  I will look into trying this.  As the document that is returned may not be the active document, I'm not sure it will work.  I will report back after trying.  Thanks.

CADbloke:  I did not use a 'using' statement for the lock process, as it might not always be applicable.  The drawing only needs to be locked if it is open within the current session by the current user.  With that being the case, I can make sure to destroy the lock like I do the database that gets created.  Thanks.

n.yuan:  The program will use a side database to complete the task if the drawing is not open within the editor by the current user when the code starts.  This is the reason for passing a document out, so that it can be locked if it happens to be open by the user when they execute the code.  Thanks.

I will try the suggested updates and report back.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Erase object by speficic layer
« Reply #5 on: December 19, 2017, 02:17:36 AM »
So it looks like you can only regen the active document, so if you launch the command from a document that has the layers it will update, but if one erases the layers in an open drawing (in the editor) that is not current the regen call will do nothing.

I have seen that I usually use a 'using' statement when operating on a drawing that is open in the editor, but is not current, so I have implemented the Destroy method on the lock object if it is not null.

Thanks all.  It seems to be working without errors or corrupting the drawings.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Erase object by speficic layer
« Reply #6 on: December 19, 2017, 09:29:27 AM »
So it looks like you can only regen the active document, so if you launch the command from a document that has the layers it will update, but if one erases the layers in an open drawing (in the editor) that is not current the regen call will do nothing.

I have seen that I usually use a 'using' statement when operating on a drawing that is open in the editor, but is not current, so I have implemented the Destroy method on the lock object if it is not null.

Thanks all.  It seems to be working without errors or corrupting the drawings.
If your talking about the UI updating when erasing a layer try opening the LayerTable for write. I think that will cause UI to update.

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: Erase object by speficic layer
« Reply #7 on: December 19, 2017, 12:40:58 PM »
So it looks like you can only regen the active document, so if you launch the command from a document that has the layers it will update, but if one erases the layers in an open drawing (in the editor) that is not current the regen call will do nothing.

You might also want to try TransactionManager.QueueForGraphicsFlush(); before you commit the transaction.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Erase object by speficic layer
« Reply #8 on: December 19, 2017, 01:21:06 PM »
Jeff H:  When I tried this, the open drawing in the editor (that is not current) did not refresh the display.

Atook:  'TransactionManager.QueueForGraphicsFlush();' caused an error 'eNotFromThisDrawing' (I think I'm correct in the error).

It is not a big problem, as it is only me using the code right now.  Thanks for trying though, it is appreciated.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.