Author Topic: Question about disposing.  (Read 14424 times)

0 Members and 1 Guest are viewing this topic.

BillZndl

  • Guest
Question about disposing.
« on: October 22, 2009, 12:15:59 PM »
VS2005, net 2.0, R2006 acad.

Trying to debug a problem with my modal form application.
Lately, when exiting AutoCAD, I sometimes get the dreaded "Fatal Error" before exit.

I've checked to be sure that I'm disposing all databases I've created and anything else outside of some "using (transaction" .

A while back, I added a global Hashtable along side (same Namespace)
as my main program form: "class public class PartMonitor : System.Windows.Forms.Form".
I use it to store info when a new group is added to the database.

public class Module
    {   
        private static Hashtable GrpInfoTable = new Hashtable();

        public static Hashtable GrpInfoTbl
        {
            get
            {
                return GrpInfoTable;
            }
        }
        public Module()
        {
        }       
    }

My question is, could the creation of this "Global" hashtable be the reason I'm getting the error?
Just wondering if somehow it needs to be "disposed"?






Glenn R

  • Guest
Re: Question about disposing.
« Reply #1 on: October 22, 2009, 12:25:31 PM »
Depends. You're not showing us enough. What's in the hashtable?

Also, have you implemented IExtensionApplication? If so, do you have anything in the Terminate method?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #2 on: October 22, 2009, 01:20:41 PM »
When an object is appended to the database event,
if it's a group, I send the e.object to be opened for read to get the name.
I add the name and either true or false to the hashtable.

using (Transaction trans = document.TransactionManager.StartTransaction())
                {               
                    DBDictionary GrpDic = (DBDictionary)trans.GetObject(db.GroupDictionaryId, OpenMode.ForRead);

                    if (GrpId.IsValid)
                    {
                        name = GrpDic.NameAt(GrpId);

                        if (!name.Contains("*"))
                        {
                            Module.GrpInfoTbl.Add(name, true);
                        }
                        else
                        {                           
                            Module.GrpInfoTbl.Add(name, false);
                        }
                    }
                    GrpDic.Dispose();
                }

Here's my IExtensionApp:

public class Initialization : Autodesk.AutoCAD.Runtime.IExtensionApplication
{
    public void Initialize()
    {
        Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
        ed.WriteMessage(" PartMon --- Loaded\r");
    }
    public void Terminate()
    {
        Console.WriteLine("Cleaning up...");
    }
}



Glenn R

  • Guest
Re: Question about disposing.
« Reply #3 on: October 22, 2009, 02:52:27 PM »
3 things I notice straight off:

1. Nix the Console.WriteLine statement in your terminate method. You don't have a console to write to and acad is shutting down fast.
2. There's no commit statement for the transaction.
3. There's no need to for this: GrpDisc.Dispose(); It will get called for you.

I suspect there's something else causing the problem, but without more information, I would only be guessing.

Try the suggestions above and see what happens and post back.

BillZndl

  • Guest
Re: Question about disposing.
« Reply #4 on: October 22, 2009, 03:45:45 PM »
Quote from: Glenn R
1. Nix the Console.WriteLine statement in your terminate method. You don't have a console to write to and acad is shutting down fast.

Saw that right after I posted.  :lol:

I changed it to this:

public void Terminate()
    {       
    }

Quote from: Glenn R
2. There's no commit statement for the transaction.

Oooh, My understanding was that you only needed to commit the transaction if you made changes,
not just accessing a name or whatever.
I had about 12 places I added the trans.commit();  :-o


Quote from:  "Glenn R"
3. There's no need to for this: GrpDisc.Dispose(); It will get called for you.

Yeah, I was deperate and trying anything I could think of. Nixed it.  :ugly:


It may take a while for these changes to show up because it doesn't happen everytime and so far it seems to help.

I'll post up if it does it again.

Thanks!



Glenn R

  • Guest
Re: Question about disposing.
« Reply #5 on: October 22, 2009, 04:06:06 PM »
After doing C++/ARX for a few years you learn a few things and one that applies equally well to .NET is this:

If you 'new' it, delete/destroy/dispose of it - if you didn't, don't. There are exceptions to this, especially in ARX where functions will hand you back a string and the documentation explicitly tells you that you're responsible for deleting the string/memory.

A .NET example would be creating a new Database for use with ReadDwgFile - you 'new'ed it, so you're responsible for disposing of it, usually by wrapping the creation in a 'using' statement/block.

You're example where you're getting a group inside a transaction shows that you didn't 'new' it, autocad did behind the scenes, so it manages it's destruction/disposal - not you.

As far as the commit goes, it's been stated by a few from autodesk, that NOT commiting a transaction is expensive because it will cause a 'rollback', so you're better off commiting the transaction, even if you're only 'reading' objects, for performance reasons, rather than implicity (in your case) or explicitly causing an abort.

Make sense?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #6 on: October 22, 2009, 04:28:46 PM »
Sure does make sense.
Helps to reinforce what I'm learning.

This app is getting fairly complicated and I am a beginner at this.
It could be a memory issue as some of my methods do a lot of looping.
One example, I was refreshing my ListView by repopulating it everytime an item changed,
which meant looping through the DBdictionary, getting names, descriptions and checking ents for visible, yada yada
I re wrote parts so I can update just one item if it changes and am getting better at modularizing(?) so am hoping that helps.

Then again, I've had R2k6 crash once in a while for no apparant reason, with no code running so go figure. :lol:

BillZndl

  • Guest
Re: Question about disposing.
« Reply #7 on: October 25, 2009, 09:40:57 PM »
Didn't help.
When I exited Autocad at the end of the day,
it really locked up with the Fatal Error.

I do have an Idea what's wrong,
I'm opening the Group for read on the DatabaseAppended event,
that's probably causing the access violation.
I'm thinking I should store the objectId and do all the work on the commandEnded event.

I'll try that and see if I'm right.



It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #8 on: October 26, 2009, 01:08:10 AM »
what happens when you run it through the debugger?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #9 on: October 26, 2009, 06:20:16 AM »
what happens when you run it through the debugger?

As far as I know, nothing. Everything builds and runs fine.

BillZndl

  • Guest
Re: Question about disposing.
« Reply #10 on: October 26, 2009, 07:50:55 AM »
I do have an Idea what's wrong,
I'm opening the Group for read on the DatabaseAppended event,
that's probably causing the access violation.
I'm thinking I should store the objectId and do all the work on the commandEnded event.

I'll try that and see if I'm right.


That didn't work.

I changed the objectId handling at the DatabaseAppended event to:
public class NewGroupObjectID
    {       
        public void GroupName(ObjectId GrpId)
        {
            if (GrpId.IsValid)
            {           
              Module.GrpInfoTbl.Add(GrpId, true);                               
            }               
        }
    }

Then I do the name and description checking at the commandEnded event but things still crashes hard at exit.





BillZndl

  • Guest
Re: Question about disposing.
« Reply #11 on: October 26, 2009, 10:18:21 AM »
Okay, this is what the error says:


My next suspect is where I delete groups, anyone see anything radiacally wrong with this class?
I feed it the group name as a string, get the group, erase the entities and remove the group from the DBdictionary.

Code: [Select]
class DeleteGroup
    {
        public void RemoveGroup(string Strline)
        {
            Document document = AcadApp.DocumentManager.MdiActiveDocument;
            Editor editor = document.Editor;
            Database database = AcadApp.DocumentManager.MdiActiveDocument.Database;

            using (DocumentLock doclck = document.LockDocument())
            {
                using (Transaction trans = database.TransactionManager.StartTransaction())
                {
                    DBDictionary GrpDic = (DBDictionary)trans.GetObject(database.GroupDictionaryId, OpenMode.ForRead);

                    ObjectId Did = ObjectId.Null;

                    try
                    {
                        Did = GrpDic.GetAt(Strline);
                    }
                    catch { }

                    if (!Did.IsNull)
                    {
                        Group EntGrpDic = (Group)trans.GetObject(Did, OpenMode.ForWrite);
                        ObjectIdCollection Eids = new ObjectIdCollection();

                        foreach (ObjectId id in EntGrpDic.GetAllEntityIds())
                        {
                            Eids.Add(id);

                            if (!id.IsErased)
                            {
                            Entity ent = (Entity)trans.GetObject(id, OpenMode.ForWrite);
                            ent.Erase();
                            }
                        }

                        if (Eids.Count > 0)
                        {
                            EntGrpDic.Remove(Eids);                           
                            database.Purge(Eids);
                        }
                        GrpDic.UpgradeOpen();
                        if (GrpDic.Contains(Did))
                        {
                        GrpDic.Remove(Did);
                        }
                       
                        Module.GrpInfoTbl.Clear();

                        editor.WriteMessage("\nDeleted Group: < " + Strline + " > \r");
                        editor.WriteMessage("\nCommand:\r");
                    }
                    trans.Commit();
                }
            }
            database.Dispose();
        }
    }

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #12 on: October 26, 2009, 10:57:28 AM »
don't do this

Code: [Select]
database.Dispose();

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #13 on: October 26, 2009, 11:30:46 AM »
A couple questions.

Why do you think you should dispose the database?
What is your try catch statement supposed to do when it catches an exception?
How are you handling exceptions that are thrown outside of your try catch scope?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #14 on: October 26, 2009, 12:25:34 PM »
A couple questions.

Why do you think you should dispose the database?

I thought I saw that in an example somewhere. < shrug >

Quote
What is your try catch statement supposed to do when it catches an exception?

Here is how I been calling my methods:
Code: [Select]
private void document_CommandEnded(object sender, CommandEventArgs e)
        {           
           
            if (e.GlobalCommandName.Equals("COPY"))
            {
                try
                {
                    AddGroupDate agd = new AddGroupDate();
                    agd.AddDate();
                    FillListView();
                    SetLastSelected();
                }
                catch (SystemException exception)
                {
                    MessageBox.Show("AddGroupDate: failed" + exception.StackTrace);
                }
            }



Quote
How are you handling exceptions that are thrown outside of your try catch scope?

That's a good question, is there a "solution level" error handler?

BTW: I took out all the DB.Dispose(); stuff and still get the error when exiting.




It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #15 on: October 26, 2009, 07:24:48 PM »
I thought I saw that in an example somewhere. < shrug >

Since you did not create the database, don't dispose it.

Here is how I been calling my methods:

That's fine, you just didn't show us the caller of your function.

have a look at this code and see if it works for you

Code: [Select]
public void RemoveGroup(string Strline)
  {
   AcAp.Document activeDocument = AcAp.Application.DocumentManager.MdiActiveDocument;
   AcEd.Editor editor = activeDocument.Editor;
   Database database = HostApplicationServices.WorkingDatabase;

   using (DocumentLock doclck = activeDocument.LockDocument())
   {
    using (Transaction trans = database.TransactionManager.StartTransaction())
    {
     DBDictionary GrpDic =
      trans.GetObject(database.GroupDictionaryId, OpenMode.ForRead) as DBDictionary;

     if (GrpDic.Contains(Strline))
     {
      ObjectId Did = ObjectId.Null;
      Did = GrpDic.GetAt(Strline);

      if (!Did.IsNull)
      {
       Group EntGrpDic = trans.GetObject(Did, OpenMode.ForWrite) as Group;
       ObjectIdCollection Eids = new ObjectIdCollection();

       foreach (ObjectId id in EntGrpDic.GetAllEntityIds())
       {
        if (!id.IsErased)
        {
         DBObject dbObject = trans.GetObject(id, OpenMode.ForWrite);
         dbObject.Erase();
        }
       }
       GrpDic.UpgradeOpen();
       GrpDic.Erase();
       editor.WriteMessage("\nDeleted Group: < " + Strline + " > \r");
       editor.WriteMessage("\nCommand:\r");
      }
      trans.Commit();
     }
    }
   }
  }


BillZndl

  • Guest
Re: Question about disposing.
« Reply #16 on: October 27, 2009, 06:48:21 AM »
Here is how I been calling my methods:

That's fine, you just didn't show us the caller of your function.

I'm glad you asked because it seems like after I added this delete and another one called explode,
my crash problems started. But it seems to crash even when I don't invoke them.

Here's how I call:

Code: [Select]
private void button9_Click(object sender, EventArgs e)
        {
            try
            {
                if (listView1.SelectedItems.Count > 0)
                {
                    RUSureDelete newRUSure = new RUSureDelete();
                    newRUSure.Visible = true;                   
                }
                else
                {
                    MessageBox.Show("Please select an item on the list:");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("RUSureDelete: " + ex.StackTrace);
            }
        }

And heres the partial class form that has 2 buttons "Yes" & "No".

Code: [Select]
public partial class RUSureDelete : Form
    {
        public RUSureDelete()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                this.Hide();
                DeleteGroup group = new DeleteGroup();
                group.RemoveGroup(PartMonitor.Instance.GetSelectedItem());
                PartMonitor.Instance.FillListView();
                PartMonitor.Instance.SetLastSelected();

            }
            catch (System.Exception exception)
            {
                MessageBox.Show("Delete Group: " + exception);
            }

        }
    }


Quote
have a look at this code and see if it works for you

I sure will.
Thanks!


BillZndl

  • Guest
Re: Question about disposing.
« Reply #17 on: October 27, 2009, 07:27:51 AM »
Quote
have a look at this code and see if it works for you

I sure will.
Thanks!


Worked great.
I did have to change GrpDic.UpgradeOpen();
                             GrpDic.Erase();

To:     EntGrpDic.Erase();

BUT... All I did was copy a couple of my groups, then delete them and on exit (and sometimes opening another drawing) KaBoom!   :-(


BillZndl

  • Guest
Re: Question about disposing.
« Reply #18 on: October 27, 2009, 02:23:52 PM »
FWIW:
I have VS2008 express set up here so I updated my solution, keeping the target as net 2.0,
It went through without a hitch and reported converting only 2 of the files (the .sln and .csproj).
Showed no errors converting but does same thing when I load it, bring it up, then exit.

I'm about out of ideas. Everything looks good to me but then again, I don't know alot.  :laugh:


Glenn R

  • Guest
Re: Question about disposing.
« Reply #19 on: October 27, 2009, 04:19:10 PM »
I've got some time on my hands at the moment, so post your solution, as the error might be generated from elsewhere in your code  and I will have a look at it.

BillZndl

  • Guest
Re: Question about disposing.
« Reply #20 on: October 27, 2009, 04:57:24 PM »
Thanks Glenn.

I sent you the zip file via PM.

Glenn R

  • Guest
Re: Question about disposing.
« Reply #21 on: October 27, 2009, 05:12:09 PM »
Do you have any specific steps that I can follow, to reproduce the fatal error?

Glenn R

  • Guest
Re: Question about disposing.
« Reply #22 on: October 27, 2009, 05:32:28 PM »
That's a fairly large project and more than I expected. Whilst I am getting my head around it, I would suggest extracting portions of it to separate projects and testing them individually to see if you can nail down the error.

Glenn R

  • Guest
Re: Question about disposing.
« Reply #23 on: October 27, 2009, 05:42:47 PM »
First thing:

Code: [Select]
Group grp = (Group)trans.GetObject(oid, OpenMode.ForRead) as Group;

You don't need a direct cast here, because you're using 'as' - stick to one or the other.

Glenn R

  • Guest
Re: Question about disposing.
« Reply #24 on: October 27, 2009, 05:46:54 PM »
Second thing:

Code: [Select]
grp.Name = string.Concat("~Copy_", grp.Name.Substring(1, 2), DateTime.Now.Millisecond.ToString());

I would use '+' to join the strings; string.Format(), or a stringbuilder.

Glenn R

  • Guest
Re: Question about disposing.
« Reply #25 on: October 27, 2009, 05:52:58 PM »
Third thing:

RUSureDelete and RUSureExplode forms are merely asking to confirm deletion - these are superfluous; use a MessageBox instead.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #26 on: October 27, 2009, 06:42:21 PM »
First thing:

Code: [Select]
Group grp = (Group)trans.GetObject(oid, OpenMode.ForRead) as Group;

You don't need a direct cast here, because you're using 'as' - stick to one or the other.

This was my bad, editing code without coffee  :ugly:

BillZndl

  • Guest
Re: Question about disposing.
« Reply #27 on: October 28, 2009, 07:01:17 AM »
Do you have any specific steps that I can follow, to reproduce the fatal error?

Lately, all I have to do is netload, type in "Partmon" command in AutoCAD,
open drawing with several part groups in it (SDI = 0) and then exit AutoCAD, KaBoom.

That's a fairly large project and more than I expected. Whilst I am getting my head around it, I would suggest extracting portions of it to separate projects and testing them individually to see if you can nail down the error.

That was my next step. I may have to strip it down to the main form and try building it back up.
I know I'm running before I can walk here but I've taken time to do research and have tested everything
before adding more to the code. Somehow this error sort of snuck up on me.

Thanks for the tips, we're using a previous release .dll of this (which doesn't crash, AFAICT)
this new version is pretty much complete to what we want it to do so I'd like to get it up & running.  

Always something huh?

First thing:
Code: [Select]
Group grp = (Group)trans.GetObject(oid, OpenMode.ForRead) as Group;
You don't need a direct cast here, because you're using 'as' - stick to one or the other.
This was my bad, editing code without coffee  :ugly:

Ah, that answers a question I asked previously.  ^-^

Thanks again.

*Edit: At least you all didn't say "what a mess, you call that code?"   :laugh:
kinda reinforces that I'm at least on the right road.  ;-)









« Last Edit: October 28, 2009, 07:12:45 AM by BillZndl »

BillZndl

  • Guest
Re: Question about disposing.
« Reply #28 on: October 28, 2009, 11:23:48 AM »
This is beginning to look like a timing issue.
I remmed out a couple of my last methods like DisplayPreview() and was working just with copying groups
with the native AutoCAD command. It was crashing when commandEnded.
The DatabaseAppend stores the ObjectId of the groups in the GlobalModule ObjectIDCollection and on the commandEnded, for copy,
the AddGroupDate() reads the OIDCollection, opens the group, checks the name, adds date etc., returns an Arraylist of the info to the AddLVItems() for a new listview item.

After copy, it was crashing so I added an editor.WriteMessage to check the names and a threadSleep(1000) to hopefully see it before it crashed,
it started working and now and with just the threadSleep, the crash no longer occurs.   :-o

Looks like it's back to the drawing board on this listView handling.
I'll probably have to re-order some things. Dunno.

« Last Edit: October 28, 2009, 11:27:06 AM by BillZndl »

BillZndl

  • Guest
Re: Question about disposing.
« Reply #29 on: October 28, 2009, 12:23:10 PM »
I did find one error.
My naming convention for anonymous groups was trying to use duplicate names
for different groups. Using the milleseconds for unique names wasn't the answer.
The loop was going too fast for that. Must've been less than a millesecond!

I'm sure i'm not out of the woods yet but at least it's progress.  :-) 


Glenn R

  • Guest
Re: Question about disposing.
« Reply #30 on: October 28, 2009, 05:34:53 PM »
*Edit: At least you all didn't say "what a mess, you call that code?"   :laugh:

Don't count your chickens as the old saying goes... :-D

Seriously, when I asked you to post your solution, what I meant was that you would post it to this thread, not send it to me in a PM, so more eyes than just mine can critique it  - if that's what you're after that is, if not, ignore this.

Can you tell me/us, what you're AutoCAD and programming background is? The reason I ask is that after a quick scan of your solution, there appears to be some fundimental language/usage errors...well, at least to me there is.

Cheers,
Glenn.

BillZndl

  • Guest
Re: Question about disposing.
« Reply #31 on: October 29, 2009, 07:22:33 AM »
Well, I didn't think it would've helped to just post my main form code without posting the rest too.
But then I didn't think it would work to try to paste everything into a post here either (it's just too much).
It probably was stupid to just dump it all on you anyway, I think I panicked. Sorry.

Again, I'm a newbie at C# and after some labs and trials I put this solution together to help us track out parts.
Most of what I've done is from the Autodesk .net site and web searches for examples/help, i.e. msdn docs & "Through the Interface".

Programming is my unofficial "side job".
I work in a manufacturing facilities engineering/CAD/CAM dept and
I've been using AutoCAD since about '92 and have programmed extensively in Autolisp almost that long.
It was getting to where I needed to learn something new with more functionality and focus on dialogs.
I thought about ObjectDCL, VB or something like that but after looking around,
decided to learn something that may have more of a future and reduce dependencies on 3rd party apps.

Everything has been a "learn as you go" experience with little formal training.
I love to program but at times I think I took on too much with C# as it is quite time consuming.
Trouble is this program works so well I hate to just abandon the whole project.  8-)

Anyway, Sorry for any inconvenience I caused and Thanks to all for your time and efforts and help!
I sure appreciate it.

I'll just keep pecking away here, I think I'm close.  ^-^



It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #32 on: October 29, 2009, 08:09:40 AM »
Just a question for you, have you actually run the code through the debugger, where you are stepping through the stack? have you tried attaching autocad to visual studio when running your code?

BillZndl

  • Guest
Re: Question about disposing.
« Reply #33 on: October 29, 2009, 08:21:37 AM »
Just a question for you, have you actually run the code through the debugger, where you are stepping through the stack? have you tried attaching autocad to visual studio when running your code?

Hmmm. Not sure what if I know how to "step through the stack".
I have run with "debug" , "start debugging" which opens AutoCAD and runs the program.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #34 on: October 29, 2009, 08:29:12 AM »
Are you setting break points and stepping though the code.. I.e

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #35 on: October 29, 2009, 08:33:17 AM »
oops sorry that's C++ but, it's  the same for C#  :-)

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Question about disposing.
« Reply #36 on: October 29, 2009, 08:35:55 AM »

must be past my bed time .. I tried to drag the locals window out of the way to see the code  :oops:
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Question about disposing.
« Reply #37 on: October 29, 2009, 08:41:53 AM »

must be past my bed time .. I tried to drag the locals window out of the way to see the code  :oops:

 :lol:

BillZndl

  • Guest
Re: Question about disposing.
« Reply #38 on: October 29, 2009, 09:37:38 AM »
I found the "mystery glitch".

Evidently, If you open a Group using it's ObjectId from a list,
you cannot change the name to the same name.

                    ObjectIdCollection OIDC = Module.GrpInfoTbl;                   

                    foreach (ObjectId oid in OIDC)
                    {               
                           
                        Group grp = trans.GetObject(oid, OpenMode.ForWrite, false, true) as Group;                       

                        string NewName = GetNewName(grp.Name, CMDName);  //check name and possibly change.                                             
                           
                        grp.Name = NewName; //Kaboom if name is the same. :?

I didn't think it mattered because you are not adding a new group with the same name, only naming an existing group.


                               

BillZndl

  • Guest
Re: Question about disposing.
« Reply #39 on: November 03, 2009, 08:27:00 AM »
Okay, I'm back. The "mystery glitch" in above post was not the end of my problems on this code.

After much testing and setting break points, all for naught, I noticed something.
When I opened AutoCAD R2006 in a blank drawing, netloaded the dll and typed in the command
to bring the modless form up, then open a drawing that contains groups (SDI=1),
the listview fills and everything looks okay but if I immediately exit autocad, the Fatal Error occurs.

My question is, I have a SelectedIndexChanged event on the listview.
Could it be possible that when I hit exit, that event is firing and trying to do something
that it can't because autocad is already shutting down?

The reason I ask is because when I disable my override on the OnClosing event so that everything disposes first,
then I can shut down autocad without any problems.

The following is so components don't dispose when you want to hide the dialog
and you call up the same instance of the dialog during the session.

protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
            e.Cancel = true;            
            Visible = false;          
        }

This is my SelectedIndexChanged event,
If I rem out the methods inside, everything exits fine:
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {            
          
           if (listView1.SelectedItems.Count > 0)
            {              

                try
                {
                    
                    //DrawPartInPicBox();
                    //SetNameDesriptionBox();
                    //DisplayPreview();                    
                }
                catch (SystemException exception)
                {
                    MessageBox.Show("SelectedIndexDrawPartInPicBox Failed:" + exception);
                }
            }            
        }

I've also found some parts of my code that needed some work so it was a good exercise in debugging.

My other question is:

Is there a way to know when a listview is able to be repopulated or can you do that at any time?

TIA

Bill




BillZndl

  • Guest
Re: Question about disposing.
« Reply #40 on: November 03, 2009, 10:30:41 AM »
I've taken it a step further:

If I rem out only the DrawPartInPicBox(); method, the crashing on exit stops.

Code: [Select]
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {       
           if (listView1.SelectedItems.Count > 0)
            {
               try
                {                     
                    //DrawPartInPicBox();
                    SetNameDesriptionBox();
                    DisplayPreview();                   
                }
                catch (SystemException exception)
                {
                    MessageBox.Show("SelectedIndexDrawPartInPicBox Failed:" + exception);
                }
            }           
        }

So that leads me to believe that's the source of the problem and it's an important part of my program.
It's what reads the entities owned by the group and draws a image of it in the picture box.
Here's the code for that, if anyone can help.
Again works fine until exit.

Code: [Select]
private void DrawPartInPicBox()
        {
            try
            {
                if (listView1.SelectedIndices.Count > 0)
                {
                    string str = GetSelectedItem();

                    if (!string.IsNullOrEmpty(str))
                    {
                        ListViewItem item = listView1.SelectedItems[0];
                        int indx = item.Index;

                        Pen pen1 = new Pen(Brushes.LightGray);
                        Pen pen2 = new Pen(Brushes.Cyan);
                        Pen pen3 = new Pen(Brushes.Yellow);
                        Pen pen4 = new Pen(Brushes.Red);
                        Pen pen5 = new Pen(Brushes.Orange);
                        Pen pen6 = new Pen(Brushes.Lime);
                        Pen pen7 = new Pen(Brushes.Magenta);

                        int width = pictureBox1.Size.Width;
                        int height = pictureBox1.Size.Height;
                        int num = 0;                            //counter.

                        string Itext = item.SubItems[0].Text;

                        Bitmap image = new Bitmap(width, height);
                        pictureBox1.Image = image;

                        Graphics graphics = Graphics.FromImage(image);
                        graphics.DrawString(item.Text, new Font("Romans", 10f), Brushes.Yellow, (PointF)new Point(3, height - 16));

                        ArrayList list1 = new GetEntityPointsToDraw().GetEnts(Itext, width, height); //Array of PointF[]'s.

                        if (list1.Count == 1)  //empty list.
                        {
                            Font fnt = new Font("Romans", 28f);
                            graphics.DrawString("GROUP EMPTY:", fnt, Brushes.DarkCyan, (PointF)new Point(8, height / 2));
                        }

                        if (list1.Count > 1)  //pointF[] lists and colorlist.
                        {
                            ArrayList list2 = list1[list1.Count - 1] as ArrayList; //colorlist from GetentityPointsToDraw.
                            list1.Remove(list1[list1.Count - 1]);                  //remove from pointF[]arraylist.

                            foreach (PointF[] tfArray in list1)         //draw each entity from points.
                            {
                                string color = list2[num].ToString();   //color of layer entity is on.
                                num++;

                                switch (color)
                                {
                                    case "White":
                                        graphics.DrawLines(pen1, tfArray);
                                        break;

                                    case "Blue":
                                        graphics.DrawLines(pen2, tfArray);
                                        break;

                                    case "Yellow":
                                        graphics.DrawLines(pen3, tfArray);
                                        break;

                                    case "Red":
                                        graphics.DrawLines(pen4, tfArray);
                                        break;

                                    case "Orange":
                                        graphics.DrawLines(pen5, tfArray);
                                        break;

                                    case "Green":
                                        graphics.DrawLines(pen6, tfArray);
                                        break;

                                    case "Magenta":
                                        graphics.DrawLines(pen7, tfArray);
                                        break;                                                                                                         

                                    default:
                                        graphics.DrawLines(pen1, tfArray);
                                        break;
                                }
                            }

                            pictureBox1.Update();

                            pen1.Dispose();
                            pen2.Dispose();
                            pen3.Dispose();
                            pen4.Dispose();
                            pen5.Dispose();
                            pen6.Dispose();
                            pen7.Dispose();
                            graphics.Dispose();

                        }
                    }                               //if str.
                }                                   //if selected indices.
            }
            catch (Exception exception)
            {
                MessageBox.Show("DrawPartInPicBox : " + exception.StackTrace);
            }
        }

I'll include the sub methods in the next post,
evidently a limit here.












BillZndl

  • Guest
Re: Question about disposing.
« Reply #41 on: November 03, 2009, 10:31:38 AM »
Here's the sub methods for DrawPartInPicBox();

And here's the sub methods that the above uses, GetEntityPointsToDraw();

Code: [Select]
class GetEntityPointsToDraw
    {

        public ArrayList GetEnts(string Strline, int Xpic, int Ypic)
        {
            
                Document doc = AcadApp.DocumentManager.MdiActiveDocument;
                Database db = HostApplicationServices.WorkingDatabase;
                Editor ed = doc.Editor;
                ArrayList Pnt3dLst = new ArrayList();
                ArrayList colorList = new ArrayList();

                string name = "";
                string LaNam = "";            

                using (DocumentLock doclck = doc.LockDocument())
                {
                    using (Transaction trans = db.TransactionManager.StartTransaction())
                    {
                        DBDictionary GrpDic = (DBDictionary)trans.GetObject(db.GroupDictionaryId, OpenMode.ForRead);

                        ObjectId Did = ObjectId.Null;

                        try
                        {
                            Did = GrpDic.GetAt(Strline);
                        }
                        catch { }

                        if (!Did.IsNull)
                        {
                            Group EntGrpDic = (Group)trans.GetObject(Did, OpenMode.ForRead);
                            ObjectId[] Eids = EntGrpDic.GetAllEntityIds();

                            foreach (ObjectId eid in Eids)
                            {
                                string color;
                                Point3d CnPnt;
                                double Rad;
                                double[] Norm;
                                Point3d[] Smpts;
                                double inc;
                                Point3d EnPnt;
                                Point3d StPnt;

                                Entity ent = (Entity)trans.GetObject(eid, OpenMode.ForRead);

                                name = ent.GetType().Name;
                                LaNam = ent.Layer;
                                color = SetColorByLayerName(LaNam.ToUpper());

                                if (color == "")
                                {
                                    name = "";
                                }

                                if (name.Equals("Arc") && LaNam.Length >= 1)
                                {
                                    AcadArc oLin = (AcadArc)ent.AcadObject;
                                    CnPnt = new Point3d((double[])oLin.Center);
                                    Rad = (double)oLin.Radius;
                                    double StAn = (double)oLin.StartAngle;
                                    double EnAn = (double)oLin.EndAngle;
                                    Norm = (double[])oLin.Normal;

                                    CircularArc3d arc = new CircularArc3d(CnPnt, new Vector3d(Norm), Rad);
                                    arc.SetAngles(StAn, EnAn);
                                    Smpts = arc.GetSamplePoints(12);
                                    Pnt3dLst.Add(Smpts);
                                    colorList.Add(color);
                                    arc.Dispose();
                                }

                                if (name.Equals("Polyline") && LaNam.Length >= 1)
                                {
                                    AcadLWPolyline oLin = (AcadLWPolyline)ent.AcadObject;
                                    Object[] aco = (Object[])oLin.Explode();
                                    AcadEntity[] acEnts = new AcadEntity[aco.Length];
                                    aco.CopyTo(acEnts, 0);

                                    foreach (AcadEntity ace in acEnts)
                                    {
                                        if (ace.ObjectName.Equals("AcDbArc"))
                                        {
                                            AcadArc arc = (AcadArc)ace;

                                            CnPnt = new Point3d((double[])arc.Center);
                                            Rad = (double)arc.Radius;
                                            double StAn = (double)arc.StartAngle;
                                            double EnAn = (double)arc.EndAngle;
                                            Norm = (double[])arc.Normal;

                                            CircularArc3d ARP = new CircularArc3d(CnPnt, new Vector3d(Norm), Rad);
                                            ARP.SetAngles(StAn, EnAn);
                                            Smpts = ARP.GetSamplePoints(12);
                                            Pnt3dLst.Add(Smpts);
                                            colorList.Add(color);
                                            ARP.Dispose();
                                        }

                                        if (ace.ObjectName.Equals("AcDbLine"))
                                        {
                                            AcadLine lin = (AcadLine)ace;

                                            StPnt = new Point3d((double[])lin.StartPoint);
                                            EnPnt = new Point3d((double[])lin.EndPoint);

                                            Smpts = new Point3d[2];
                                            Smpts[0] = StPnt;
                                            Smpts[1] = EnPnt;
                                            Pnt3dLst.Add(Smpts);
                                            colorList.Add(color);
                                        }
                                    }
                                }

                                if (name.Equals("Circle") && LaNam.Length >= 1)
                                {
                                    AcadCircle oLin = (AcadCircle)ent.AcadObject;
                                    CnPnt = new Point3d((double[])oLin.Center);
                                    Rad = (double)oLin.Radius;
                                    Norm = (double[])oLin.Normal;

                                    double perm = (double)oLin.Circumference;
                                    double dist = (perm / 11); //segments of cricle.
                                    inc = dist;
                                    Circle circ = new Circle(CnPnt, new Vector3d(Norm), Rad);
                                    Smpts = new Point3d[12];

                                    for (int x = 0; x < 12; x++)
                                    {
                                        Point3d pt = circ.GetPointAtDist(inc);
                                        Smpts[x] = pt;
                                        inc = inc + dist;
                                    }
                                    Pnt3dLst.Add(Smpts);
                                    colorList.Add(color);
                                    circ.Dispose();
                                }
                                if (name.Equals("DBPoint") && LaNam.Length >= 1)
                                {
                                    AcadPoint oLin = (AcadPoint)ent.AcadObject;
                                    CnPnt = new Point3d((double[])oLin.Coordinates);
                                    Norm = (double[])oLin.Normal;
                                    double distance = 0.1;
                                    double angle = 0.0;
                                    inc = (Math.PI * 0.5);

                                    Smpts = new Point3d[] { PolarPoint(CnPnt, angle, distance), PolarPoint(CnPnt, Math.PI, distance) };
                                    Pnt3dLst.Add(Smpts);
                                    colorList.Add(color);
                                    Smpts = new Point3d[] { PolarPoint(CnPnt, inc, distance), PolarPoint(CnPnt, (Math.PI + inc), distance) };
                                    Pnt3dLst.Add(Smpts);
                                    colorList.Add(color);
                                }

                                if (name.Equals("Ellipse") && LaNam.Length >= 1)
                                {
                                    AcadEllipse oLin = (AcadEllipse)ent.AcadObject;
                                    CnPnt = new Point3d((double[])oLin.Center);
                                    EnPnt = new Point3d((double[])oLin.EndPoint);
                                    StPnt = new Point3d((double[])oLin.StartPoint);
                                    Norm = (double[])oLin.Normal;

                                    Vector3d MaAx = new Vector3d((double[])oLin.MajorAxis);
                                    Vector3d MnAx = new Vector3d((double[])oLin.MinorAxis);

                                    double MaRad = (double)oLin.MajorRadius;
                                    double MnRad = (double)oLin.MinorRadius;
                                    double EnAn = (double)oLin.EndAngle;
                                    double StAn = (double)oLin.StartAngle;
                                    double RR = (double)oLin.RadiusRatio;

                                    EllipticalArc3d arc = new EllipticalArc3d(CnPnt, MaAx, MnAx, MaRad, MnRad, StAn, EnAn);

                                    Smpts = arc.GetSamplePoints(50);

                                    Pnt3dLst.Add(Smpts);
                                    colorList.Add(color);
                                    arc.Dispose();

                                }

                                if (name.Equals("Spline") && LaNam.Length >= 1)
                                {

                                    AcadSpline oLin = (AcadSpline)ent.AcadObject;
                                    Point3dCollection fpts = new Point3dCollection();
                                    Vector3d v1 = new Vector3d((double[])oLin.StartTangent);
                                    Vector3d v2 = new Vector3d((double[])oLin.EndTangent);

                                    for (int x = 0; x < oLin.NumberOfFitPoints; x++)
                                    {
                                        fpts.Add(new Point3d((double[])oLin.GetFitPoint(x)));
                                    }

                                    CubicSplineCurve3d spl = new CubicSplineCurve3d(fpts, v1, v2);

                                    Smpts = spl.GetSamplePoints(50);
                                    Pnt3dLst.Add(Smpts);
                                    colorList.Add(color);
                                    spl.Dispose();

                                }

                                if (name.Equals("Line") && LaNam.Length >= 1)
                                {
                                    AcadLine oLin = (AcadLine)ent.AcadObject;
                                    StPnt = new Point3d((double[])oLin.StartPoint);
                                    EnPnt = new Point3d((double[])oLin.EndPoint);

                                    Smpts = new Point3d[2];
                                    Smpts[0] = StPnt;
                                    Smpts[1] = EnPnt;
                                    Pnt3dLst.Add(Smpts);
                                    colorList.Add(color);
                                }                //if

                            }          //foreach item in group dictionary.                        
                        }                      //ObjectId not null from group dictionary.                    
                    }        //using transaction.                
                }      //using document lock.                

                ArrayList NewArray = PointsToPicBox(Pnt3dLst, Xpic, Ypic); //PointF[] Array returned.
                NewArray.Add(colorList);                                   //Add color list.
                return NewArray;                              
            
        }

        /// <summary>
        /// Translates & converts point3d to pointF's
        /// </summary>
        /// <param name="Pnt3dLst"></param>
        /// <param name="Xpic"></param>
        /// <param name="Ypic"></param>        
        /// <returns></returns>

        private ArrayList PointsToPicBox(ArrayList Pnt3dLst, int Xpic, int Ypic)
        {
            ArrayList PntFLst = new ArrayList();                    //PointF's for picbox.

            Matrix3d MatD = new Matrix3d();                         //displacement            
            Matrix3d MatT = new Matrix3d();                         //transformation
            Matrix3d MatS = new Matrix3d();                         //scaling    
            Matrix3d MatR = new Matrix3d();                         //scaling    

            Point3d VwDir = (Point3d)AcadApp.GetSystemVariable("VIEWDIR");              
                        
            Plane pln = new Plane(new Point3d(0, 0, 0), VwDir.GetAsVector().Negate());

            MatT = Matrix3d.WorldToPlane(pln);      

            ArrayList Pnt2dLst = ConvertPtsTo2D(Pnt3dLst, MatT);

            PointF min = new Point(1000000, 1000000);
            PointF max = new Point(-1000000, -1000000);

            foreach (Point2d[] pts in Pnt2dLst)            //ArrayList of Point2d's.
            {
                foreach (Point2d pnt in pts)
                {
                    PointF pt = new PointF((float)pnt.X, (float)pnt.Y);
                    min = new PointF(pt.X < min.X ? pt.X : min.X, pt.Y < min.Y ? pt.Y : min.Y); //minimum XY point.
                    max = new PointF(pt.X > max.X ? pt.X : max.X, pt.Y > max.Y ? pt.Y : max.Y); //maximum XY point.

                }
            }  

            double VwExtX = max.X - min.X;
            double VwExtY = max.Y - min.Y;
            double SclFac;


            if ((VwExtX * 0.850) >= VwExtY)                    //X distance of points greater in proportion to Y?
            {
                SclFac = (Xpic / VwExtX * 0.95);                    //scale X if greatest length.
            }
            else
            {
                SclFac = (Ypic / VwExtY * 0.95);                    //scale to Y if not X.
            }            

            Point3d p1 = new Point3d(min.X + (VwExtX / 2.0), min.Y + (VwExtY / 2.0), 0);       //center of part point.            
            Point3d p2 = new Point3d(Xpic / 2.0, Ypic / 2.0, 0);                               //center of picbox.                

            MatS = Matrix3d.Scaling(SclFac, p2);                                               //scale pointlist to picbox.        
            MatD = Matrix3d.Displacement(p2.GetVectorTo(p1));                                  //displacement.            
            MatR = Matrix3d.Rotation(Math.PI, new Vector3d(0, 0, 1), p1);                      //rotate.
            MatS = MatS * MatD * MatR;

            Point3d NewPt = new Point3d();            

            foreach (Point3d[] pts in Pnt3dLst)                                 //ArrayList of PointF[]'s.
                {
                    PointF[] PntFs = new PointF[pts.Length];

                    for (int x = 0; x < pts.Length; x++)
                    {
                        NewPt = pts[x].TransformBy(MatS * MatT);
                        PntFs[x] = new PointF((float)NewPt.X, (float)NewPt.Y);
                    }

                    PntFLst.Add(PntFs);
                }      

            return PntFLst;                                      //ArrayList of pointF[]'s.
                              
        }


        private ArrayList ConvertPtsTo2D (ArrayList Pnts, Matrix3d MatToPln)
        {

            ArrayList Pt2dLst = new ArrayList();
            Point3d TempPt = new Point3d();
                
                foreach (Point3d[] pts in Pnts)             //ArrayList of Point3d[]'s.
                {
                    Point2d[] Pnts2d = new Point2d[pts.Length];

                    for (int x = 0; x < pts.Length; x++)
                    {                        
                        TempPt = pts[x].TransformBy(MatToPln);
                        Pnts2d[x] = new Point2d(TempPt.X, TempPt.Y);
                    }

                    Pt2dLst.Add(Pnts2d);
                }

                return Pt2dLst;
        }


        private string SetColorByLayerName(string str)
        {
            string color = "";

            switch (str)
            {
                case "0":
                    color = "White";
                    break;

                case "BEND":
                    color = "White";
                    break;

                case "CLEAR":
                    color = "Green";
                    break;

                case "HID":
                    color = "Magenta";
                    break;

                case "LDRILL":
                    color = "Blue";
                    break;

                case "NAIL":
                    color = "Yellow";
                    break;

                case "OUTSIDE":
                    color = "Red";
                    break;

                case "PH":
                    color = "Orange";
                    break;

                default:
                    color = "";                    
                    break;
            }
            return color;
        }        

        public Point3d PolarPoint(Point3d basepoint, double angle, double distance)
        {
            return new Point3d(basepoint.X + (distance * Math.Cos(angle)), basepoint.Y + (distance * Math.Sin(angle)), basepoint.Z);
        }

Any help appreciated.

Bill

BillZndl

  • Guest
Re: Question about disposing.
« Reply #42 on: November 03, 2009, 02:05:13 PM »
Well, FWIW, I think I finally found the problem.

I was looking at GetEntityPointsToDraw() and saw what could be trouble.
After the:

Entity ent = (Entity)trans.GetObject(eid, OpenMode.ForRead);

I added a null entity check:

if (ent != null)
 {

and the problem went away. :roll:

I know that I still don't have all this code down properly.
We started this program to replace one that we had that was written in Autolisp.
We were originally using Blocks and when I first wrote this in C#
it was a lot simpler using blocks.
I sort of slapped this one together because our need to have this program was great.

Anyway, I'm still looking to learn how to do things correctly so if anyone has any pointers, feel free to instruct. :)




foreach (ObjectId eid in Eids)
                            {
                                string color;
                                Point3d CnPnt;
                                double Rad;
                                double[] Norm;
                                Point3d[] Smpts;
                                double inc;
                                Point3d EnPnt;
                                Point3d StPnt;

                                Entity ent = (Entity)trans.GetObject(eid, OpenMode.ForRead);

                                if (ent != null)
                                {

BillZndl

  • Guest
Re: Question about disposing.
« Reply #43 on: November 04, 2009, 02:41:26 PM »
Just an update in case anyones been following my flounderings. :grazy:
I think I was just doing too much during certain events.

If I just use the FillListView() on the document activated event and don't use the SetLastSelected() or any other method
and just leave it to the user to select an item, so the SelectedIndexChanged event does the DrawPartInPicBox()
and the DisplayPreview(), things are working alot better.  :-)

I don't know enough to say for sure but it seems to me that there was some sycronization or timing issues involved when I tried to fill the listview and set the last group and display the preview and draw the part in the picturebox all in succession on the document activated. :doa:


I may just put the SetLastSelected() on a button in case one wants to find that last group created.
for some reason it seems like that one gives me trouble when it's activated several times during the drawing and I can't see why.
Code: [Select]
public class LastGroupInDrawing
    {
        public string FindLastGroup()
        {

            Document doc = AcadApp.DocumentManager.MdiActiveDocument;
            Database db = HostApplicationServices.WorkingDatabase;           

            using (DocumentLock dloc = doc.LockDocument())
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    DBDictionary groups = (DBDictionary)tr.GetObject(db.GroupDictionaryId, OpenMode.ForRead);
                    ObjectId grpId = ObjectId.Null;
                   
                    grpId = GetNewest(groups);

                    if (!grpId.IsNull)
                    {                       
                        return groups.NameAt(grpId);
                    }
                    else
                    {
                        return "No";
                    }                                 
                }               
            }         
        }

        public ObjectId GetNewest(DBDictionary dictionary)
        {
            ICollection ids = ((IDictionary)dictionary).Values;
            ObjectId last = ObjectId.Null;

            foreach (ObjectId temp in ids)
            {
                last = temp;
                break;
            }

            if (!last.IsNull)
            {
                long current = last.Handle.Value;

                foreach (ObjectId id in ids)
                {
                    long value = id.Handle.Value;

                    if (value > current)
                    {
                        current = value;
                        last = id;
                    }
                }               
            }           
            return last;
        }
    }

As time permits, I'll study my O'Reilly's C# book and hopefully learn more about all this.

For now the bottom line is, it works, just gotta hit qsave often to be safe.   :whistle:


Glenn R

  • Guest
Re: Question about disposing.
« Reply #44 on: November 05, 2009, 01:27:51 PM »
Is that book by Jesse Liberty? If so, I was going to suggest it as a beginners book.

When you're ready to move to a more advanced book, myself and others here recommend Andrew Troelsen's 'Pro C# and the .NET 3.5 Platform' - it's excellent.

These languages are not like lisp where you can just 'hack away' - you need to put in the effort of learning the groundwork of the language and it's usage.

Keep at it - it is fun!

BillZndl

  • Guest
Re: Question about disposing.
« Reply #45 on: November 05, 2009, 02:44:18 PM »
Is that book by Jesse Liberty? If so, I was going to suggest it as a beginners book.

When you're ready to move to a more advanced book, myself and others here recommend Andrew Troelsen's 'Pro C# and the .NET 3.5 Platform' - it's excellent.

These languages are not like lisp where you can just 'hack away' - you need to put in the effort of learning the groundwork of the language and it's usage.

Keep at it - it is fun!

Yes, Jesse Liberty, net 1.1 & vs 2003.

We're just so used to slapping something together with lisp to solve our problems.
But this has been fun and rewarding.
All part of the learning curve.
Believe it or not, I've come a long way already.  :-D

Thanks again everyone!

Bill





BillZndl

  • Guest
Re: Question about disposing.
« Reply #46 on: November 17, 2009, 04:53:41 PM »
have a look at this code and see if it works for you

Code: [Select]
      if (!Did.IsNull)
      {
       Group EntGrpDic = trans.GetObject(Did, OpenMode.ForWrite) as Group;
       ObjectIdCollection Eids = new ObjectIdCollection();

       foreach (ObjectId id in EntGrpDic.GetAllEntityIds())
       {
        if (!id.IsErased)
        {
         DBObject dbObject = trans.GetObject(id, OpenMode.ForWrite);
         dbObject.Erase();
        }
       }
       [color=red]GrpDic.UpgradeOpen();
       GrpDic.Erase();[/color]
       editor.WriteMessage("\nDeleted Group: < " + Strline + " > \r");
       editor.WriteMessage("\nCommand:\r");
      }
      trans.Commit();
     }
 

Seems like I still have to purge the database of the erased items to keep AutoCAD happy.
And I'm not sure if I have to remove the objectId of the group from the group dictionary,
I'll have test it some more and see about that.
Other wise things are working pretty good but I plan to keep reading and refining my abilities.  :laugh:
Thanks!

Code: [Select]
if (!Did.IsNull)
                        {
                            Group EntGrpDic = trans.GetObject(Did, OpenMode.ForWrite) as Group;
                            [color=red]ObjectIdCollection oidc = new ObjectIdCollection(EntGrpDic.GetAllEntityIds());[/color]

                            foreach (ObjectId id in EntGrpDic.GetAllEntityIds())
                            {
                                if (!id.IsErased)
                                {
                                    DBObject dbObject = trans.GetObject(id, OpenMode.ForWrite);
                                    dbObject.Erase();                                   
                                }
                            }

                            [color=red]GrpDic.UpgradeOpen();
                            GrpDic.Remove(Did);
                            GrpDic.DowngradeOpen();

                            database.Purge(oidc);
                            EntGrpDic.Erase();
                            oidc.Dispose();[/color]
                           
                            editor.WriteMessage("\nDeleted Group: < " + Strline + " > \r");
                            editor.WriteMessage("\nCommand:\r");
                        }