Insert block with attributes into a side database

Insert block with attributes into a side database

Keith.Brown
Advisor Advisor
3,109 Views
2 Replies
Message 1 of 3

Insert block with attributes into a side database

Keith.Brown
Advisor
Advisor

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.

 

/// <summary>
/// Inserts a block into the specified Space.
/// </summary>
/// <param name="blockName">Name of the block to insert.</param>
/// <param name="insertionPoint">The insertion point of the block.</param>
/// <param name="database">The database to work in.</param>
/// <param name="space">The space to insert into</param>
/// <param name="attributes">The attributes to set on the block.</param>
/// <exception cref="System.ArgumentNullException">blockName;The block name cannot be empty</exception>
/// <exception cref="Autodesk.AutoCAD.Runtime.Exception">The database cannot be null.
/// or
/// The block does not exist in the current database.</exception>
/// <exception cref="Exception">
/// The block does not exist in the current database.
/// </exception>
public static void InsertBlock(string blockName, Point3d insertionPoint, Database database, Space space, Dictionary<string, string> attributes) 
{
   if (string.IsNullOrWhiteSpace(blockName))
   {
      throw new ArgumentNullException("blockName", "The block name cannot be empty");
   }
 
 
   if (database == null)
   {
      throw new Exception(ErrorStatus.NoDatabase, "The database cannot be null.");
   }
 
 
   using (var transaction = database.TransactionManager.TopTransaction)
   {
      if (transaction == null)
      {
         throw new Exception(ErrorStatus.NotTopTransaction);
      }
 
 
      var blockTable = (BlockTable)database.BlockTableId.GetObject(OpenMode.ForRead);
      if (!blockTable.Has(blockName))
      {
         throw new Exception(ErrorStatus.NotInDatabase, "The block does not exist in the current database.");
      }
 
 
      var blockDefinition = (BlockTableRecord)blockTable[blockName].GetObject(OpenMode.ForRead);
 
      using (var blockReference = new BlockReference(insertionPoint, blockDefinition.ObjectId))
      {
         try
         {
            BlockTableRecord currentSpace;
            if (space == Space.ModelSpace)
            {
               currentSpace = (BlockTableRecord)blockTable[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite);
            }
            else
            {
               currentSpace = (BlockTableRecord)blockTable[BlockTableRecord.PaperSpace].GetObject(OpenMode.ForWrite);
            }
 
 
            currentSpace.AppendEntity(blockReference);
 
 
            transaction.AddNewlyCreatedDBObject(blockReference, true);
            foreach (var objectId in blockDefinition)
            {
               var dbObject = objectId.GetObject(OpenMode.ForRead);
               var attributeDefinition = dbObject as AttributeDefinition;
               if ((attributeDefinition != null) && (!attributeDefinition.Constant))
               {
                  if (attributes.ContainsKey(attributeDefinition.Tag))
                  {
                     using (var attributeReference = new AttributeReference())
                     {
                        try
                        {
                           attributeReference.SetAttributeFromBlock(attributeDefinition, blockReference.BlockTransform);
                           attributeReference.Position = attributeDefinition.Position.TransformBy(blockReference.BlockTransform);
                           attributeReference.TextString = attributes[attributeDefinition.Tag];
 
 
                           blockReference.AttributeCollection.AppendAttribute(attributeReference);
                           transaction.AddNewlyCreatedDBObject(attributeReference, true);
                        }
                        catch (Exception exception)
                        {
                           Log.Logger.Error(exception, "Unable to set attribute {Attribute} on block {blockName}", attributeDefinition.TextString, blockName);
                        }
                     }
                  }
               }
            }
         }
         catch (Exception exception)
         {
            Log.Logger.Error(exception, "Unable to insert the block {blockName} into the drawing {fileName}.", blockName, database.Filename);
            throw new Exception(ErrorStatus.UnrecoverableErrors, string.Format("Unable to insert block {0} into {1}.", blockName, database.Filename), exception.InnerException);
         }
      }
   }
} 

Here are the commands to run the code.

 

/// <summary>
/// Imports a block and inserts it into the current drawing.
/// </summary>
[CommandMethod("My Examples", "ImportAndInsertBlockIntoActiveDrawing", CommandFlags.Session)]
public void ImportAndInsertBlockIntoActiveDrawingCSharpCommand()
{
   var database = Active.Database;
 
 
   using (Active.Document.LockDocument())
   using (var transaction = database.TransactionManager.StartTransaction())
   {
      var objectId = BlockUtils.ImportBlock("test", @"C:\Users\kbrown\Desktop\TestBlock.dwg", database, DuplicateRecordCloning.Replace);
      if (objectId != ObjectId.Null)
      {
         var attributes = new Dictionary<string, string> { { "SCALE", "1/8\" = 1'-0\"" }, { "TITLE", "This is where the title block goes." } };
         BlockUtils.InsertBlock("test", new Point3d(0, 0, 0), database, Space.PaperSpace, attributes);
      } 
      else
      {
         MessageBox.Show("Unable to import the block.", "Import Error!");
      }
 
 
      transaction.Commit();
   } 
}
 
 
/// <summary>
/// Imports the block and inserts it into a side drawing.
/// </summary>
[CommandMethod("My Examples", "ImportAndInsertBlockIntoSideDrawing", CommandFlags.Session)]
public void ImportAndInsertBlockIntoSideDrawingCSharpCommand()
{
   const string FileName = @"C:\Users\kbrown\Desktop\TempTestDrawing.dwg";
   var database = new Database();
   database.ReadDwgFile(FileName, FileOpenMode.OpenForReadAndAllShare, true, string.Empty);
   database.SaveAs(FileName, DwgVersion.Current);
 
   using (var transaction = database.TransactionManager.StartTransaction())
   {
      var objectId = BlockUtils.ImportBlock("test", @"C:\Users\kbrown\Desktop\TestBlock.dwg", database, DuplicateRecordCloning.Replace);
      if (objectId != ObjectId.Null)
      {
         var attributes = new Dictionary<string, string> { { "SCALE", "1/8\" = 1'-0\"" }, { "TITLE", "This is where the title block goes." } };
         BlockUtils.InsertBlock("test", new Point3d(0, 0, 0), database, Space.PaperSpace, attributes);
      }
 
 
      transaction.Commit();
      database.SaveAs(FileName, DwgVersion.Current);
   }
}

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

0 Likes
Accepted solutions (1)
3,110 Views
2 Replies
Replies (2)
Message 2 of 3

_gile
Consultant
Consultant
Accepted solution

Hi,

 

No time to check what's wrong with your code, but the following code works for me.

Maybe you can get some inspiration...

 

Some extension methods:

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.IO;
using AcRx = Autodesk.AutoCAD.Runtime;

namespace ImportBlock
{
    static class BlockUtils
    {
        public static ObjectId GetBlock(this BlockTable blockTable, string blockName)
        {
            if (blockTable == null)
                throw new ArgumentNullException("blockTable");

            Database db = blockTable.Database;
            if (blockTable.Has(blockName))
                return blockTable[blockName];

            try
            {
                string ext = Path.GetExtension(blockName);
                if (ext == "")
                    blockName += ".dwg";
                string blockPath;
                if (File.Exists(blockName))
                    blockPath = blockName;
                else
                    blockPath = HostApplicationServices.Current.FindFile(blockName, db, FindFileHint.Default);

                blockTable.UpgradeOpen();
                using (Database tmpDb = new Database(false, true))
                {
                    tmpDb.ReadDwgFile(blockPath, FileShare.Read, true, null);
                    return blockTable.Database.Insert(Path.GetFileNameWithoutExtension(blockName), tmpDb, true);
                }
            }
            catch
            {
                return ObjectId.Null;
            }
        }

        public static BlockReference InsertBlockReference(
            this BlockTableRecord target,
            string blkName,
            Point3d insertPoint,
            Dictionary<string, string> attValues = null)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            Database db = target.Database;
            Transaction tr = db.TransactionManager.TopTransaction;
            if (tr == null)
                throw new AcRx.Exception(ErrorStatus.NoActiveTransactions);

            BlockReference br = null;
            BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

            ObjectId btrId = bt.GetBlock(blkName);

            if (btrId != ObjectId.Null)
            {
                br = new BlockReference(insertPoint, btrId);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
                target.AppendEntity(br);
                tr.AddNewlyCreatedDBObject(br, true);

                br.AddAttributeReferences(attValues);
            }
            return br;
        }

        public static void AddAttributeReferences(this BlockReference target, Dictionary<string, string> attValues)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            Transaction tr = target.Database.TransactionManager.TopTransaction;
            if (tr == null)
                throw new AcRx.Exception(ErrorStatus.NoActiveTransactions);

            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(target.BlockTableRecord, OpenMode.ForRead);
            RXClass attDefClass = RXClass.GetClass(typeof(AttributeDefinition));

            foreach (ObjectId id in btr)
            {
                if (id.ObjectClass != attDefClass)
                    continue;
                AttributeDefinition attDef = (AttributeDefinition)tr.GetObject(id, OpenMode.ForRead);
                AttributeReference attRef = new AttributeReference();
                attRef.SetAttributeFromBlock(attDef, target.BlockTransform);
                if (attValues != null && attValues.ContainsKey(attDef.Tag.ToUpper()))
                {
                    attRef.TextString = attValues[attDef.Tag.ToUpper()];
                }
                target.AttributeCollection.AppendAttribute(attRef);
                tr.AddNewlyCreatedDBObject(attRef, true);
            }
        }
    }
}

Testing commands

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System.Collections.Generic;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(ImportBlock.Commands))]

namespace ImportBlock
{
    public class Commands
    {
        [CommandMethod("Cmd1")]
        public void Cmd1()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                ObjectId btrId = bt.GetBlock(@"F:\gile\Gile_blocs\bloc-att.dwg");
                if (btrId == ObjectId.Null)
                    return;
                Dictionary<string, string> attValues = new Dictionary<string,string>();
                attValues.Add("ATT1", "foo");
                attValues.Add("ATT2", "bar");
                BlockTableRecord curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                BlockReference br = curSpace.InsertBlockReference("bloc-att", Point3d.Origin, attValues);
                tr.Commit();
            }
        }
        [CommandMethod("Cmd2")]
        public void Cmd2()
        {
            const string filename = @"F:\gile\TestDrawing.dwg";

            using (Database db = new Database(false, true))
            {
                db.ReadDwgFile(filename, System.IO.FileShare.ReadWrite, false, null);
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                    ObjectId btrId = bt.GetBlock(@"F:\gile\Gile_blocs\bloc-att.dwg");
                    if (btrId == ObjectId.Null)
                        return;
                    Dictionary<string, string> attValues = new Dictionary<string, string>();
                    attValues.Add("ATT1", "foo");
                    attValues.Add("ATT2", "bar");
                    BlockTableRecord curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    BlockReference br = curSpace.InsertBlockReference("bloc-att", Point3d.Origin, attValues);
                    tr.Commit();
                }
                db.SaveAs(filename, DwgVersion.Current);
            }
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 3

Keith.Brown
Advisor
Advisor

Thanks Gile.  Through your code i was able to figure out that the code that I had posted had nothing wrong with it.  The issue was with the importing of blocks.  I was using wblock clone to go out into a drawing and bring in a specific block.  Somehow this is/was causing an ewrongdatabase exception whenever I was appending the attribute references to the block reference but only in a side database.  Instead of tracing it down I just did something similar to your GetBlock function.  I just imported the entire dwg as a block instead.  If and when i need multiple blocks inserted into a side database from the same drawing i will revisit the issue.  Until then what I have is working great.

 

Thanks for the help.

0 Likes