Author Topic: Help with WBlockCloneObjects  (Read 14808 times)

0 Members and 1 Guest are viewing this topic.

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Help with WBlockCloneObjects
« on: March 08, 2011, 05:32:13 PM »
Attached is a VS2008-C# project. It is a stripped down version of something I've been working on for a while now. At one time, this code (or something close to it is more like it) worked. While streamlining and doing other things that I thought were unrelated, I've managed to break it. I've been staring at it for 2 days now, finally ripping out what I'm posting here down to the minimums.

The idea is to create a table in the current drawing which shows an image and description (ok, a legend of sorts) of the Blocks being used in either A) The current drawing, B) All Open drawings, or C) Drawings selected by the user. Option A works just fine. Options B & C DID work on most, if not all, drawings. Then it started not working.....it goes through all the correct motions of gathering the blocks from other drawings, copying the definitions to the start dwg, and asking for the insertion point of the Table....Sometimes it will place the table ok, other times it will Fatal Error during the table creation. On those occasions where the table IS created, any attempt to zoom which requires a regen causes the Fatal Error.

Since I did have this working at one time, I'm thinking there is something obvious that I'm just not seeing.....and I'm hoping that someone with a fresh set of eyes and a little bit of time can have a look for me. I'd sure appreciate whatever insights anyone can offer. For anyone daring to try it on it's own, the compiled dll (for Acad2010) is included which can be Netload'ed, and the command name is LegendTest.

I used the ObjectArx2010 32 bit AutoCAD managed references. Although I think this should probably also work if those were changed to 2011.

Thanks!
« Last Edit: March 09, 2011, 12:45:01 PM by Jeff_M »

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Help with WBlockCloneObjects
« Reply #1 on: March 08, 2011, 05:56:06 PM »
I noticed on some of my code that when working with an open drawing, that wasn't current, I had to lock that document.  I didn't see you locking any document but the one calling the program.  Maybe that will help.
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: Help with WBlockCloneObjects
« Reply #2 on: March 08, 2011, 06:47:23 PM »
Have not looked at it but tables changed in 2010 or 2011.

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #3 on: March 08, 2011, 06:53:35 PM »
Thanks Tim & Jeff for the quick comments.

Tim, just tried locking all documents, no change.

Jeff, the tables create fine in 2010. In fact I can comment out the code for the tables, then manually attempt to insert one of the imported blocks and get the same Fatal Error.  My next step was to get this working in 2011 as well, but since this version isn't yet working.....

So this tells me that somehow I am mucking up the BlockTable, which the only way I can do that is by my use of WBlockCloneObjects (I think).

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #4 on: March 08, 2011, 07:15:27 PM »
I am trying it on a2011 - is not even let me select the insertion point (there is some { missing? right after:
           
PromptPointResult pr = ed.GetPoint("\nLegend Table insertion point: ");

below your call to PromptStatus.OK

Still can't pass after that line... will give it another try later...

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Help with WBlockCloneObjects
« Reply #5 on: March 08, 2011, 07:18:38 PM »
I get the designer can not be shown for this file error.

Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #6 on: March 08, 2011, 07:38:57 PM »
Luis, I'm getting the same as you in 2011. There is no missing { }'s because there is only one item after the "if", that being the "using" so this should work just fine (and does in 2010).

Stepping through the code in 2011, this line never pauses for input:
                PromptPointResult pr = ed.GetPoint("\nLegend Table insertion point: ");
instead it automatically returns Cancel.

Jeff, I got that when I first ripped it out of the bigger program. Try building before opening the Form in the editor.
« Last Edit: March 08, 2011, 07:43:40 PM by Jeff_M »

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #7 on: March 08, 2011, 07:40:50 PM »
Test under A2011 using the autocad assemblies (that come with the acad.exe installation, since these are not available in the ARX SDK)

If I insert the table at a predefined point, it works, no problems.
Code: [Select]
           //PromptPointOptions ppo = new PromptPointOptions("\nLegend Table insertion point: "); // test only
            //ppo.AllowArbitraryInput = false;
            //ppo.AllowNone = false;

            //PromptPointResult pr = ed.GetPoint(ppo); //"\nLegend Table insertion point: ");
            //if (pr.Status != PromptStatus.OK) return;

            Point3d pt = Point3d.Origin; // <<<<
                
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
                if (!btr.Name.ToUpper().Equals("*MODEL_SPACE"))
                    scale = 1.0;
                ObjectId tblId;
                if (lb_LegendTable.SelectedIndex != -1)
                {
                    DBDictionary nod = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                    DBDictionary dict = (DBDictionary)tr.GetObject(nod.GetAt("ACAD_TABLESTYLE"), OpenMode.ForRead);
                    tblId = (ObjectId)dict[lb_LegendTable.SelectedValue.ToString()];
                }
                else
                    tblId = db.Tablestyle;

                TableStyle tstyle = (TableStyle)tr.GetObject(tblId, OpenMode.ForRead);
                double titleHgt = tstyle.TextHeight(RowType.TitleRow) * scale;
                double headerHgt = tstyle.TextHeight(RowType.HeaderRow) * scale;
                double dataHgt = tstyle.TextHeight(RowType.DataRow) * scale;
                double hzMrgn = tstyle.HorizontalCellMargin * scale;
                double vrtMrgn = tstyle.VerticalCellMargin * scale;

                AcDb.Table legendtbl = new AcDb.Table();
                double rowHgt = dataHgt + (2.0 * vrtMrgn);
                double colOneWdth = headerHgt * 7.0; //6 characters in SYMBOL + 1 for spacing
                double colTwoWdth = dataHgt * maxdesclength;
                legendtbl.TableStyle = tblId;
                legendtbl.InsertRows(1, rowHgt, blklist.Count + 1);
                legendtbl.VerticalCellMargin = vrtMrgn;
                legendtbl.HorizontalCellMargin = hzMrgn;
                legendtbl.DeleteColumns(0, 3);
                legendtbl.InsertColumns(0, colOneWdth, 1);
                legendtbl.InsertColumns(1, colTwoWdth, 1);
                legendtbl.Cells.Borders.Bottom.IsVisible = false;
                legendtbl.Cells.Borders.Horizontal.IsVisible = false;
                legendtbl.Cells.Borders.Left.IsVisible = false;
                legendtbl.Cells.Borders.Right.IsVisible = false;
                legendtbl.Cells.Borders.Top.IsVisible = false;
                legendtbl.Cells.Borders.Vertical.IsVisible = false;
                legendtbl.Rows[0].Height = titleHgt + (2.0 * vrtMrgn);
                legendtbl.Rows[0].TextHeight = titleHgt;
                legendtbl.Rows[1].TextHeight = headerHgt;
                legendtbl.Cells[0, 0].TextString = "Symbol Legend";
                legendtbl.Cells[1, 0].TextString = "Symbol";
                legendtbl.Cells[1, 1].TextString = "Denotes";
                legendtbl.Cells[1, 0].Alignment = CellAlignment.MiddleCenter;
                legendtbl.Cells[1, 1].Alignment = CellAlignment.MiddleLeft;
                legendtbl.SuppressRegenerateTable(true);
                for (int i = 0; i < blklist.Count; i++)
                {
                    BlockTableRecord blkid = (BlockTableRecord)tr.GetObject(usedBlks[blklist[i]], OpenMode.ForRead);
                    string desc = blkid.Comments;
                    if (desc == "")
                        desc = blklist[i];
                    //legendtbl.Cells[i + 2, 0].VerticalLine.Margin = vrtMrgn; //This doesn't work even though we are told to use it...2010
                    legendtbl.Cells[i + 2, 0].BlockTableRecordId = usedBlks[blklist[i]];
                    legendtbl.Cells[i + 2, 1].TextString = desc;
                    legendtbl.Rows[i + 2].TextHeight = dataHgt;
                    legendtbl.Cells[i + 2, 0].Alignment = CellAlignment.MiddleCenter;
                    legendtbl.Cells[i + 2, 1].Alignment = CellAlignment.MiddleLeft;
                }
                legendtbl.SuppressRegenerateTable(false);
                legendtbl.Position = pt; //pr.Value; <<<<<

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Help with WBlockCloneObjects
« Reply #8 on: March 08, 2011, 08:09:44 PM »
When I do all drawings here at

Code: [Select]


            Document doc = AcApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            double scale = 20.0;

            List<string> blklist = usedBlks.Keys.ToList<string>();
            blklist.Sort();
                PromptPointResult pr = ed.GetPoint("\nLegend Table insertion point: ");
                if (pr.Status == PromptStatus.OK)

The doc is set temp/s$rty/.........
Some temp file
So pr.status is false and skips over
So to figure maybe if this is this  is the problem and where the doc is being set improperly

LE3

  • Guest
Re: Help with WBlockCloneObjects
« Reply #9 on: March 08, 2011, 08:12:46 PM »
Now, if I remove the command session flag, and make the drawing current manually it works if I also add this line: legendtbl.GenerateLayout()
And by doing the above, I can define the insertion point too.

So it is something about making active the drawing, where the table it is going to be placed...
Code: [Select]
   [CommandMethod("LegendTest")] //, CommandFlags.Session)] // test only
        public void LegendBuilderCommand()

Code: [Select]
           PromptPointOptions ppo = new PromptPointOptions("\nLegend Table insertion point: ");
            ppo.AllowArbitraryInput = false;
            ppo.AllowNone = false;

            PromptPointResult pr = ed.GetPoint(ppo); //"\nLegend Table insertion point: ");
            if (pr.Status != PromptStatus.OK) return;

            //Point3d pt = Point3d.Origin;
                
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
                if (!btr.Name.ToUpper().Equals("*MODEL_SPACE"))
                    scale = 1.0;
                ObjectId tblId;
                if (lb_LegendTable.SelectedIndex != -1)
                {
                    DBDictionary nod = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                    DBDictionary dict = (DBDictionary)tr.GetObject(nod.GetAt("ACAD_TABLESTYLE"), OpenMode.ForRead);
                    tblId = (ObjectId)dict[lb_LegendTable.SelectedValue.ToString()];
                }
                else
                    tblId = db.Tablestyle;

                TableStyle tstyle = (TableStyle)tr.GetObject(tblId, OpenMode.ForRead);
                double titleHgt = tstyle.TextHeight(RowType.TitleRow) * scale;
                double headerHgt = tstyle.TextHeight(RowType.HeaderRow) * scale;
                double dataHgt = tstyle.TextHeight(RowType.DataRow) * scale;
                double hzMrgn = tstyle.HorizontalCellMargin * scale;
                double vrtMrgn = tstyle.VerticalCellMargin * scale;

                AcDb.Table legendtbl = new AcDb.Table();
                double rowHgt = dataHgt + (2.0 * vrtMrgn);
                double colOneWdth = headerHgt * 7.0; //6 characters in SYMBOL + 1 for spacing
                double colTwoWdth = dataHgt * maxdesclength;
                legendtbl.TableStyle = tblId;
                legendtbl.InsertRows(1, rowHgt, blklist.Count + 1);
                legendtbl.VerticalCellMargin = vrtMrgn;
                legendtbl.HorizontalCellMargin = hzMrgn;
                legendtbl.DeleteColumns(0, 3);
                legendtbl.InsertColumns(0, colOneWdth, 1);
                legendtbl.InsertColumns(1, colTwoWdth, 1);
                legendtbl.Cells.Borders.Bottom.IsVisible = false;
                legendtbl.Cells.Borders.Horizontal.IsVisible = false;
                legendtbl.Cells.Borders.Left.IsVisible = false;
                legendtbl.Cells.Borders.Right.IsVisible = false;
                legendtbl.Cells.Borders.Top.IsVisible = false;
                legendtbl.Cells.Borders.Vertical.IsVisible = false;
                legendtbl.Rows[0].Height = titleHgt + (2.0 * vrtMrgn);
                legendtbl.Rows[0].TextHeight = titleHgt;
                legendtbl.Rows[1].TextHeight = headerHgt;
                legendtbl.Cells[0, 0].TextString = "Symbol Legend";
                legendtbl.Cells[1, 0].TextString = "Symbol";
                legendtbl.Cells[1, 1].TextString = "Denotes";
                legendtbl.Cells[1, 0].Alignment = CellAlignment.MiddleCenter;
                legendtbl.Cells[1, 1].Alignment = CellAlignment.MiddleLeft;
                legendtbl.SuppressRegenerateTable(true);
                for (int i = 0; i < blklist.Count; i++)
                {
                    BlockTableRecord blkid = (BlockTableRecord)tr.GetObject(usedBlks[blklist[i]], OpenMode.ForRead);
                    string desc = blkid.Comments;
                    if (desc == "")
                        desc = blklist[i];
                    //legendtbl.Cells[i + 2, 0].VerticalLine.Margin = vrtMrgn; //This doesn't work even though we are told to use it...2010
                    legendtbl.Cells[i + 2, 0].BlockTableRecordId = usedBlks[blklist[i]];
                    legendtbl.Cells[i + 2, 1].TextString = desc;
                    legendtbl.Rows[i + 2].TextHeight = dataHgt;
                    legendtbl.Cells[i + 2, 0].Alignment = CellAlignment.MiddleCenter;
                    legendtbl.Cells[i + 2, 1].Alignment = CellAlignment.MiddleLeft;
                }
                legendtbl.SuppressRegenerateTable(false);
                legendtbl.Position = pr.Value; //pt
                
                legendtbl.GenerateLayout(); // <<<<

                btr.UpgradeOpen();

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Help with WBlockCloneObjects
« Reply #10 on: March 08, 2011, 08:21:41 PM »
If I select All open drawings and one drawing is open works.

If more than one open say E101 and E102 and do all open drawings

If E102 is current drawing @ C:\Drawings\E102.dwg a
It will create another drawing @  C:\User\Apdata\Temp\E102.Dwg
with same name just different location and that is the database it is trying to insert legend into at previous post

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Help with WBlockCloneObjects
« Reply #11 on: March 09, 2011, 07:44:38 AM »
This helped or made it work on this end for selecting all open drawings

After debugging a little I thought it had something to do with  locking the doc and the doc changing


commenting out  //AcApp.DocumentManager.MdiActiveDocument = opndoc;
got it working here
Code: [Select]
foreach (Document opndoc in AcApp.DocumentManager)
                    {
                        //now get the blocks in all other drawings, except the LegendDWG
                        if (doc.Name != opndoc.Name)
                        {
                            //AcApp.DocumentManager.MdiActiveDocument = opndoc;
                            gatherdatafromDWG(db, opndoc.Database);
                        }
                    }


Jeff_M

  • King Gator
  • Posts: 4087
  • C3D user & customizer
Re: Help with WBlockCloneObjects
« Reply #12 on: March 09, 2011, 01:02:31 PM »
Thanks for testing this out guys. There are a few things that are a "must" for this overall program to work.

The biggest is that each document must be set current in order to work with the Civil3D API. There is a huge amount of code that relies on this so it's not something I can do without. (The Civil3D API only works in the context of Current Document).

The next is that in order to make each document current, the CommandFlags.Session and DocLock must be used, at least everything I've read, and tested, thus far says so.

I'm attaching a revised project that simplifies the code. I no longer include the form or the Table creation code. So now it's down to just assuming the user has at least 2 drawings open (one in the background must have block insertions, the current dwg can be essentially empty), then run the command and it loops thru all open drawings leaving you back at the command prompt in the original drawing with Done! in the command line. This works in both 2010 and 2011. Now for the fun part, use the Insert command and select one of the blocks that did not exist in this drawing before running the BlockTest command, set the Insertion Point and Rotation options to "Specify on screen". You should see the "jig" for the block, while you pick the insertion point and rotation angle. What happens next is where we see that something is amiss...... Note that I changed the command name for this version.

With this trimmed down code I'm hoping it will be easier to spot where I went astray... Thanks again for any pointers you might have. Oh, it is currently set for a 2011 build.

Jeff, I do see in 2011 that there appears to be a 'new' drawing added to the doc collection based on the Icons in the taskbar. However, while debugging and walking thru the code, the Documents Collection Count never changes. This very well may be were things are tripping up, but I'm not seeing any way to deal with this.
« Last Edit: March 09, 2011, 01:08:08 PM by Jeff_M »

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Help with WBlockCloneObjects
« Reply #13 on: March 09, 2011, 01:12:59 PM »
Jeff, I do see in 2011 that there appears to be a 'new' drawing added to the doc collection based on the Icons in the taskbar. However, while debugging and walking thru the code, the Documents Collection Count never changes. This very well may be were things are tripping up, but I'm not seeing any way to deal with this.

It did not do it on 64-bit I do not think.

You should be able to switch documents and lock them but

Lock Document
Create Form
Method....
Method....
Method....
Method....
Method....
Method....
End Lock

Instead Lock only when making modification then disposeing imediatley
I am about to download new version and have toying around with something similiar, but If you do not mind I might take parts of youra and itergrate them with what I was working and post back.

If that is okay with you of course

T.Willey

  • Needs a day job
  • Posts: 5251
Re: Help with WBlockCloneObjects
« Reply #14 on: March 09, 2011, 02:34:01 PM »
The new version worked here in '09 Electrical.
Tim

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

Please think about donating if this post helped you.