Author Topic: Insert block with attributes into a side database  (Read 2428 times)

0 Members and 1 Guest are viewing this topic.

Keith Brown

  • Swamp Rat
  • Posts: 601
Insert block with attributes into a side database
« on: July 20, 2015, 10:45:47 AM »
I have been unsuccessful with trying to insert a block with attributes into a side database.  I have been able to insert one successfully into an active database but not a side one.  Here is my insert block code.



Code - C#: [Select]
  1. /// <summary>
  2. /// Inserts a block into the specified Space.
  3. /// </summary>
  4. /// <param name="blockName">Name of the block to insert.</param>
  5. /// <param name="insertionPoint">The insertion point of the block.</param>
  6. /// <param name="database">The database to work in.</param>
  7. /// <param name="space">The space to insert into</param>
  8. /// <param name="attributes">The attributes to set on the block.</param>
  9. /// <exception cref="System.ArgumentNullException">blockName;The block name cannot be empty</exception>
  10. /// <exception cref="Autodesk.AutoCAD.Runtime.Exception">The database cannot be null.
  11. /// or
  12. /// The block does not exist in the current database.</exception>
  13. /// <exception cref="Exception">
  14. /// The block does not exist in the current database.
  15. /// </exception>
  16. public static void InsertBlock(string blockName, Point3d insertionPoint, Database database, Space space, Dictionary<string, string> attributes)
  17. {
  18.    if (string.IsNullOrWhiteSpace(blockName))
  19.    {
  20.       throw new ArgumentNullException("blockName", "The block name cannot be empty");
  21.    }
  22.  
  23.  
  24.    if (database == null)
  25.    {
  26.       throw new Exception(ErrorStatus.NoDatabase, "The database cannot be null.");
  27.    }
  28.  
  29.  
  30.    using (var transaction = database.TransactionManager.TopTransaction)
  31.    {
  32.       if (transaction == null)
  33.       {
  34.          throw new Exception(ErrorStatus.NotTopTransaction);
  35.       }
  36.  
  37.  
  38.       var blockTable = (BlockTable)database.BlockTableId.GetObject(OpenMode.ForRead);
  39.       if (!blockTable.Has(blockName))
  40.       {
  41.          throw new Exception(ErrorStatus.NotInDatabase, "The block does not exist in the current database.");
  42.       }
  43.  
  44.  
  45.       var blockDefinition = (BlockTableRecord)blockTable[blockName].GetObject(OpenMode.ForRead);
  46.      
  47.       using (var blockReference = new BlockReference(insertionPoint, blockDefinition.ObjectId))
  48.       {
  49.          try
  50.          {
  51.             BlockTableRecord currentSpace;
  52.             if (space == Space.ModelSpace)
  53.             {
  54.                currentSpace = (BlockTableRecord)blockTable[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite);
  55.             }
  56.             else
  57.             {
  58.                currentSpace = (BlockTableRecord)blockTable[BlockTableRecord.PaperSpace].GetObject(OpenMode.ForWrite);
  59.             }
  60.  
  61.  
  62.             currentSpace.AppendEntity(blockReference);
  63.  
  64.  
  65.             transaction.AddNewlyCreatedDBObject(blockReference, true);
  66.             foreach (var objectId in blockDefinition)
  67.             {
  68.                var dbObject = objectId.GetObject(OpenMode.ForRead);
  69.                var attributeDefinition = dbObject as AttributeDefinition;
  70.                if ((attributeDefinition != null) && (!attributeDefinition.Constant))
  71.                {
  72.                   if (attributes.ContainsKey(attributeDefinition.Tag))
  73.                   {
  74.                      using (var attributeReference = new AttributeReference())
  75.                      {
  76.                         try
  77.                         {
  78.                            attributeReference.SetAttributeFromBlock(attributeDefinition, blockReference.BlockTransform);
  79.                            attributeReference.Position = attributeDefinition.Position.TransformBy(blockReference.BlockTransform);
  80.                            attributeReference.TextString = attributes[attributeDefinition.Tag];
  81.  
  82.  
  83.                            blockReference.AttributeCollection.AppendAttribute(attributeReference);
  84.                            transaction.AddNewlyCreatedDBObject(attributeReference, true);
  85.                         }
  86.                         catch (Exception exception)
  87.                         {
  88.                            Log.Logger.Error(exception, "Unable to set attribute {Attribute} on block {blockName}", attributeDefinition.TextString, blockName);
  89.                         }
  90.                      }
  91.                   }
  92.                }
  93.             }
  94.          }
  95.          catch (Exception exception)
  96.          {
  97.             Log.Logger.Error(exception, "Unable to insert the block {blockName} into the drawing {fileName}.", blockName, database.Filename);
  98.             throw new Exception(ErrorStatus.UnrecoverableErrors, string.Format("Unable to insert block {0} into {1}.", blockName, database.Filename), exception.InnerException);
  99.          }
  100.       }
  101.    }
  102. }


Here are the commands to run the code.


Code - C#: [Select]
  1. /// <summary>
  2. /// Imports a block and inserts it into the current drawing.
  3. /// </summary>
  4. [CommandMethod("My Examples", "ImportAndInsertBlockIntoActiveDrawing", CommandFlags.Session)]
  5. public void ImportAndInsertBlockIntoActiveDrawingCSharpCommand()
  6. {
  7.    var database = Active.Database;
  8.  
  9.  
  10.    using (Active.Document.LockDocument())
  11.    using (var transaction = database.TransactionManager.StartTransaction())
  12.    {
  13.       var objectId = BlockUtils.ImportBlock("test", @"C:\Users\kbrown\Desktop\TestBlock.dwg", database, DuplicateRecordCloning.Replace);
  14.       if (objectId != ObjectId.Null)
  15.       {
  16.          var attributes = new Dictionary<string, string> { { "SCALE", "1/8\" = 1'-0\"" }, { "TITLE", "This is where the title block goes." } };
  17.          BlockUtils.InsertBlock("test", new Point3d(0, 0, 0), database, Space.PaperSpace, attributes);
  18.       }
  19.       else
  20.       {
  21.          MessageBox.Show("Unable to import the block.", "Import Error!");
  22.       }
  23.  
  24.  
  25.       transaction.Commit();
  26.    }
  27. }
  28.  
  29.  
  30. /// <summary>
  31. /// Imports the block and inserts it into a side drawing.
  32. /// </summary>
  33. [CommandMethod("My Examples", "ImportAndInsertBlockIntoSideDrawing", CommandFlags.Session)]
  34. public void ImportAndInsertBlockIntoSideDrawingCSharpCommand()
  35. {
  36.    const string FileName = @"C:\Users\kbrown\Desktop\TempTestDrawing.dwg";
  37.    var database = new Database();
  38.    database.ReadDwgFile(FileName, FileOpenMode.OpenForReadAndAllShare, true, string.Empty);
  39.    database.SaveAs(FileName, DwgVersion.Current);
  40.    
  41.    using (var transaction = database.TransactionManager.StartTransaction())
  42.    {
  43.       var objectId = BlockUtils.ImportBlock("test", @"C:\Users\kbrown\Desktop\TestBlock.dwg", database, DuplicateRecordCloning.Replace);
  44.       if (objectId != ObjectId.Null)
  45.       {
  46.          var attributes = new Dictionary<string, string> { { "SCALE", "1/8\" = 1'-0\"" }, { "TITLE", "This is where the title block goes." } };
  47.          BlockUtils.InsertBlock("test", new Point3d(0, 0, 0), database, Space.PaperSpace, attributes);
  48.       }
  49.  
  50.  
  51.       transaction.Commit();
  52.       database.SaveAs(FileName, DwgVersion.Current);
  53.    }
  54. }


As I mentioned before inserting into an active database works with no issues.  Inserting into a side database will insert the block but no attributes.  If i open the drawing afterwards and insert the block then the attributes work normal so i know that there is nothing wrong with my import function.  (at least i belive that is a true statement).


Anyone have any ideas? Thanks.


Drawing with block to place on desktop.  (Make sure to change filename string to point to correct location if downloading for testing.)
TestBlock.dwg
« Last Edit: July 20, 2015, 01:39:37 PM by Keith Brown »
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Insert block with attributes into a side database
« Reply #1 on: July 20, 2015, 04:20:26 PM »
Hi Keith,

I replied you here.
Speaking English as a French Frog

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Insert block with attributes into a side database
« Reply #2 on: July 21, 2015, 11:35:16 AM »
Thanks Gile.


For anyone else following this thread I could not find much wrong with the code that I was using other then the way that I was importing the block into the side database.  I was using wblockclone to bring in an individual block from a drawing.  Once i switched to importing the entire dwg as a block instead it started working well.  At this point I am unsure if it was just the way i was wblocking (which i copied code from Kean's blog) or if it was something internally wrong with either mine or autodesk's api.  For those wondering I was getting an ewrongdatabase exception when I was appending the attribute references to the block reference.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Insert block with attributes into a side database
« Reply #3 on: July 21, 2015, 08:29:22 PM »
i DON'T know how you got it to work without "dbase.ReadDwgFile(sFile, System.IO.FileShare.ReadWrite,false,null);" (the readwrite" ) I played around with it and couldn't find what was up. Very fussy.
 Confusing warning from help
Quote
This function should only be used on a newly created Database that was created with its constructor's buildDefaultDrawing argument set to false. If this method is used on an Database that was created with buildDefaultDrawing set to true, or an Database that already has information in it (for any reason including a previous call to this function), then memory leaks, or worse, will result.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: Insert block with attributes into a side database
« Reply #4 on: July 22, 2015, 11:17:16 AM »
Somehow between the original post and getting it to work that line was changed to include the false and the null.  I do not remember changing nor do i remember ever setting it to true.  That being said it was pseudo working.  It would insert a block with geometry it just would not update the attributes.  So not really sure why it was doing that much at least.


If i have time today I will go back and play around with my original getblock method and see if that would have worked correctly if I had just changed the database.  I believe that it probably will and the whole problem I had was how I setup the side database.


Thanks for the help Bryco.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: Insert block with attributes into a side database
« Reply #5 on: July 23, 2015, 12:01:15 AM »
The AWOL Attributes thing may be ATTSYNC related or, if the block name already exists in the drawing (as a Definition, not necessarily as an Insert) then it will take on the existing definition. If it's not inserted you could purge it before re-inserting it.