.NET

Reply
Active Contributor
zhangxinhua789
Posts: 32
Registered: ‎01-29-2013
Message 1 of 9 (2,682 Views)
Accepted Solution

how to use a Block Properties Table of a a Dynamic Block using .NET API?

2682 Views, 8 Replies
03-07-2013 04:52 AM

Hello,experts
I have a  question,It's about "Block Properties Table",I want to use a Block Properties Table to manage a Dynamic
Block.

I  have defiened a Dynamic Block a and its Block Properties Table in Autocad2010,this is the screenshot of the
Block Properties Table(a1:d1=100,d2=200;a2:d1=100,d2=400;a3:d1=100,d2=600.)
Now I want to insert the Dynamic Block using .NET API.after I input a command,the block of a2(d1=100,d2=400)
is inserted.
I have  the code about it from Help,but the code is not complete,Can you help me finish the code which can achieve my goal?
Thank you very much!

this is the Dynamic Block

1.png

this is the  the screenshot of the Block Properties Table

2.png

the result:

3.png

the code about it from Help:

[CommandMethod("readBlockTable")]

static public void CmdReadBlockTable()

{

  Editor ed = Application.DocumentManager.

    MdiActiveDocument.Editor;

 

  // select a block reference

  PromptEntityOptions peo = new PromptEntityOptions(

    "Select a dynamic block reference: ");

  peo.SetRejectMessage("Only block reference");

  peo.AddAllowedClass(typeof(BlockReference), false);

  PromptEntityResult per = ed.GetEntity(peo);

  if (per.Status != PromptStatus.OK) return;

  ObjectId blockRefId = per.ObjectId;

 

  // get the database and start a transaction

  Database db = Application.DocumentManager.

    MdiActiveDocument.Database;

  using (Transaction trans = db.

    TransactionManager.StartTransaction())

  {

    // open the dynamic block reference

    BlockReference blockRef = trans.GetObject(

      blockRefId, OpenMode.ForRead) as BlockReference;

    if (!blockRef.IsDynamicBlock) return;

 

    // get the dynamic block table definition

    BlockTableRecord blockDef = trans.GetObject(

      blockRef.DynamicBlockTableRecord,

      OpenMode.ForRead) as BlockTableRecord;

 

    // open the extension dictionary

    if (blockDef.ExtensionDictionary.IsNull) return;

    DBDictionary extDic = trans.GetObject(

      blockDef.ExtensionDictionary, OpenMode.ForRead)

      as DBDictionary;

 

    // open the ENHANCEDBLOCK dictionary

    Autodesk.AutoCAD.Internal.DatabaseServices.EvalGraph graph =

      trans.GetObject(extDic.GetAt("ACAD_ENHANCEDBLOCK"),

      OpenMode.ForRead) as EvalGraph;

 

    int[] nodeIds = graph.GetAllNodes();

    foreach (uint nodeId in nodeIds)

    {

      // open the node ID

      DBObject node = graph.GetNode(nodeId,

        OpenMode.ForRead, trans);

      // check is if the correct type

      if (!(node is BlockPropertiesTable)) continue;

      // convert the object

      BlockPropertiesTable table =

        node as BlockPropertiesTable;

 

      // ok, we have the data, let's show it...

 

      // get the number of columns

      int columns = table.Columns.Count;

      int currentRow = 0;

      foreach (

        BlockPropertiesTableRow row

        in table.Rows)

      {

           currentRow++;

      }

    }

  }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I've done minimum tests with provided dwg-file:

 

using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Internal.DatabaseServices;
using AcAp = Autodesk.AutoCAD.ApplicationServices;
using AcDb = Autodesk.AutoCAD.DatabaseServices;
using AcGe = Autodesk.AutoCAD.Geometry;
using AcEd = Autodesk.AutoCAD.EditorInput;
using AcId = Autodesk.AutoCAD.Internal.DatabaseServices;
[assembly: CommandClass(typeof(Rivilis.BPTTest))]
#pragma warning disable 618
namespace Rivilis
{
public class BPTTest
{
[CommandMethod("InsBlockWithBPT")]
public static void InsBlockWithBPT()
{
AcAp.Document doc = AcAp.Application.DocumentManager.MdiActiveDocument;
AcEd.Editor ed = doc.Editor;
AcDb.Database db = doc.Database;
AcEd.PromptResult rs = ed.GetString("\nEnter block name: ");
if (rs.Status != PromptStatus.OK) return;
AcDb.ObjectId idBTR = AcDb.ObjectId.Null, idBref;
using (AcDb.BlockTable bt = db.BlockTableId.Open(OpenMode.ForRead) as AcDb.BlockTable) {
if (bt != null) idBTR = bt[rs.StringResult];
}
if (idBTR.IsNull) {
ed.WriteMessage("\nDatabase has not block \"{0}\"", rs.StringResult);
return;
}
AcEd.PromptPointResult rsp = ed.GetPoint("\nEnter position: ");
if (rsp.Status != PromptStatus.OK) return;
using (AcDb.Transaction tr = doc.TransactionManager.StartTransaction()) {
AcDb.BlockTableRecord btr =
tr.GetObject(idBTR, OpenMode.ForRead) as AcDb.BlockTableRecord;
AcDb.BlockTableRecord btrSpace =
tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as AcDb.BlockTableRecord;
if (btr != null && btrSpace != null) {
AcDb.BlockReference brf =
new AcDb.BlockReference(rsp.Value.TransformBy(ed.CurrentUserCoordinateSystem), idBTR);
idBref = btrSpace.AppendEntity(brf);
tr.AddNewlyCreatedDBObject(brf, true);
if (brf.IsDynamicBlock) {
AcDb.BlockTableRecord btrDyn =
tr.GetObject(brf.DynamicBlockTableRecord, OpenMode.ForRead) as AcDb.BlockTableRecord;
if (btrDyn != null && !btrDyn.ExtensionDictionary.IsNull) {
AcDb.DBDictionary extDic =
tr.GetObject(btrDyn.ExtensionDictionary, OpenMode.ForRead) as AcDb.DBDictionary;
if (extDic != null) {
AcId.EvalGraph graph =
tr.GetObject(extDic.GetAt("ACAD_ENHANCEDBLOCK"), OpenMode.ForRead) as AcId.EvalGraph;
int[] nodeIds = graph.GetAllNodes();
foreach (uint nodeId in nodeIds) {
DBObject node = graph.GetNode(nodeId, OpenMode.ForRead, tr);
if (!(node is BlockPropertiesTable)) continue;
AcDb.BlockPropertiesTable bpt = node as AcDb.BlockPropertiesTable;
int currentRow = SelectRowNumber(ref bpt);
AcDb.BlockPropertiesTableRow row = bpt.Rows[currentRow];
List<string> nameProps = new List<string>();
for (int i = 0; i < bpt.Columns.Count; i++) {
nameProps.Add(bpt.Columns[i].Parameter.Name);
}
AcDb.DynamicBlockReferencePropertyCollection dynPropsCol =
brf.DynamicBlockReferencePropertyCollection;
foreach (AcDb.DynamicBlockReferenceProperty dynProp in dynPropsCol) {
int i = nameProps.FindIndex(delegate(string s) { return s == dynProp.PropertyName; });
if (i >= 0 && i < nameProps.Count) {
try {
dynProp.Value = row[i].AsArray()[0].Value;
} catch {
ed.WriteMessage("\nCan not set to {0} value={1}",
dynProp.PropertyName, row[i].AsArray()[0].Value);
}
}
}
}
}
}
} else {
ed.WriteMessage("\nBlock \"{0}\" is not dynamic", rs.StringResult);
}
}
tr.Commit();
}
}
public static int SelectRowNumber(ref BlockPropertiesTable bpt)
{
AcEd.Editor ed = AcAp.Application.DocumentManager.MdiActiveDocument.Editor;
int columns = bpt.Columns.Count;
int rows = bpt.Rows.Count;
int currentRow = 0, currentColumn = 0;
ed.WriteMessage("\n");
for (currentColumn = 0; currentColumn < columns; currentColumn++) {
ed.WriteMessage("{0}; ", bpt.Columns[currentColumn].Parameter.Name);
}
foreach (BlockPropertiesTableRow row in bpt.Rows) {
ed.WriteMessage("\n[{0}]:\t", currentRow);
for (currentColumn = 0; currentColumn < columns; currentColumn++) {
TypedValue[] columnValue = row[currentColumn].AsArray();
foreach (TypedValue tpVal in columnValue) {
ed.WriteMessage("{0}; ", tpVal.Value);
}
ed.WriteMessage("|");
}
currentRow++;
}
AcEd.PromptIntegerResult res;
string.Format("0-{0}", rows - 1);
while ((res = ed.GetInteger(string.Format("\nSelect row number (0-{0}): ", rows - 1))).Status == PromptStatus.OK) {
if (res.Value >= 0 && res.Value <= rows) return res.Value;
}
return -1;
}
}
}

 

Moderator
Alexander.Rivilis
Posts: 1,417
Registered: ‎04-09-2008
Message 2 of 9 (2,665 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 07:02 AM in reply to: zhangxinhua789

I've done minimum tests with provided dwg-file:

 

using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Internal.DatabaseServices;
using AcAp = Autodesk.AutoCAD.ApplicationServices;
using AcDb = Autodesk.AutoCAD.DatabaseServices;
using AcGe = Autodesk.AutoCAD.Geometry;
using AcEd = Autodesk.AutoCAD.EditorInput;
using AcId = Autodesk.AutoCAD.Internal.DatabaseServices;

[assembly: CommandClass(typeof(Rivilis.BPTTest))]

#pragma warning disable 618

namespace Rivilis
{

  public class BPTTest
  {
    [CommandMethod("InsBlockWithBPT")]
    public static void InsBlockWithBPT()
    {
      AcAp.Document doc = AcAp.Application.DocumentManager.MdiActiveDocument;
      AcEd.Editor ed = doc.Editor;
      AcDb.Database db = doc.Database;
      AcEd.PromptResult rs = ed.GetString("\nEnter block name: ");
      if (rs.Status != PromptStatus.OK) return;
      AcDb.ObjectId idBTR = AcDb.ObjectId.Null, idBref;
      using (AcDb.BlockTable bt = db.BlockTableId.Open(OpenMode.ForRead) as AcDb.BlockTable) {
        if (bt != null) idBTR = bt[rs.StringResult];
      }
      if (idBTR.IsNull) {
        ed.WriteMessage("\nDatabase has not block \"{0}\"", rs.StringResult);
        return;
      }
      AcEd.PromptPointResult rsp = ed.GetPoint("\nEnter position: ");
      if (rsp.Status != PromptStatus.OK) return;

      using (AcDb.Transaction tr = doc.TransactionManager.StartTransaction()) {
        AcDb.BlockTableRecord btr = 
          tr.GetObject(idBTR, OpenMode.ForRead) as AcDb.BlockTableRecord;
        AcDb.BlockTableRecord btrSpace = 
          tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as AcDb.BlockTableRecord;
        if (btr != null && btrSpace != null) {
          AcDb.BlockReference brf =
            new AcDb.BlockReference(rsp.Value.TransformBy(ed.CurrentUserCoordinateSystem), idBTR);
          idBref = btrSpace.AppendEntity(brf);
          tr.AddNewlyCreatedDBObject(brf, true);
          if (brf.IsDynamicBlock) {
            AcDb.BlockTableRecord btrDyn =
              tr.GetObject(brf.DynamicBlockTableRecord, OpenMode.ForRead) as AcDb.BlockTableRecord;
            if (btrDyn != null && !btrDyn.ExtensionDictionary.IsNull) {
              AcDb.DBDictionary extDic = 
                tr.GetObject(btrDyn.ExtensionDictionary, OpenMode.ForRead) as AcDb.DBDictionary;
              if (extDic != null) {
                AcId.EvalGraph graph =
                  tr.GetObject(extDic.GetAt("ACAD_ENHANCEDBLOCK"), OpenMode.ForRead) as AcId.EvalGraph;
                int[] nodeIds = graph.GetAllNodes();
                foreach (uint nodeId in nodeIds) {
                  DBObject node = graph.GetNode(nodeId, OpenMode.ForRead, tr);
                  if (!(node is BlockPropertiesTable)) continue;
                  AcDb.BlockPropertiesTable bpt = node as AcDb.BlockPropertiesTable;
                  int currentRow = SelectRowNumber(ref bpt);
                  AcDb.BlockPropertiesTableRow row = bpt.Rows[currentRow];
                  List<string> nameProps = new List<string>();
                  for (int i = 0; i < bpt.Columns.Count; i++) {
                    nameProps.Add(bpt.Columns[i].Parameter.Name);
                  }
                  AcDb.DynamicBlockReferencePropertyCollection dynPropsCol =
                    brf.DynamicBlockReferencePropertyCollection;
                  foreach (AcDb.DynamicBlockReferenceProperty dynProp in dynPropsCol) {
                    int i = nameProps.FindIndex(delegate(string s) { return s == dynProp.PropertyName; });
                    if (i >= 0 && i < nameProps.Count) {
                      try { 
                        dynProp.Value = row[i].AsArray()[0].Value;
                      } catch {
                        ed.WriteMessage("\nCan not set to {0} value={1}", 
                          dynProp.PropertyName, row[i].AsArray()[0].Value);
                      }
                    }
                  }
                }
              }
            }
          } else {
            ed.WriteMessage("\nBlock \"{0}\" is not dynamic", rs.StringResult);
          }
        }
        tr.Commit();
      }
    }

    public static int SelectRowNumber(ref BlockPropertiesTable bpt)
    {
      AcEd.Editor ed = AcAp.Application.DocumentManager.MdiActiveDocument.Editor;
      int columns = bpt.Columns.Count;
      int rows = bpt.Rows.Count;
      int currentRow = 0, currentColumn = 0;
      ed.WriteMessage("\n");
      for (currentColumn = 0; currentColumn < columns; currentColumn++) {
        ed.WriteMessage("{0}; ", bpt.Columns[currentColumn].Parameter.Name);
      }
      foreach (BlockPropertiesTableRow row in bpt.Rows) {
        ed.WriteMessage("\n[{0}]:\t", currentRow);
        for (currentColumn = 0; currentColumn < columns; currentColumn++) {
          TypedValue[] columnValue = row[currentColumn].AsArray();
          foreach (TypedValue tpVal in columnValue) {
            ed.WriteMessage("{0}; ", tpVal.Value);
          }
          ed.WriteMessage("|");
        }
        currentRow++;
      }

      AcEd.PromptIntegerResult res;
      string.Format("0-{0}", rows - 1);

      while ((res = ed.GetInteger(string.Format("\nSelect row number (0-{0}): ", rows - 1))).Status == PromptStatus.OK) {
        if (res.Value >= 0 && res.Value <= rows) return res.Value;
      }
      return -1;
    }
  }
}

 


Пожалуйста не забывайте про Утвердить в качестве решения! Утвердить в качестве решения и Give Kudos!Баллы
Please remember to Accept Solution! Accept as Solution and Give Kudos!Kudos

Mentor
khoa.ho
Posts: 213
Registered: ‎09-15-2011
Message 3 of 9 (2,652 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 12:24 PM in reply to: zhangxinhua789

Dynamic block uses the extension dictionary ACAD_ENHANCEDBLOCK in DynamicBlockTableRecord to store all dynamic block definitions (grips, visibility values,...), and DynamicBlockReferencePropertyCollection in BlockReference to stores instances of those dynamic definitions.

 

Your Block Properties Table with three defined columns (user1, d1, d2) is stored in ACAD_ENHANCEDBLOCK, and the option of this Block Properties Table is stored in DynamicBlockReferencePropertyCollection. So to change the display of this dynamic block, you just set DynamicBlockReferenceProperty.Value of a found DynamicBlockReferenceProperty.Name.

 

The Block Properties Table inside the dynamic block uses the first column (user1) as a key field to identify the presentation of this block, so just use the code snippet to update its dynamic attribute: if PropertyName == "user1" then Value = "a3"

 

using (Transaction trans = db.TransactionManager.StartTransaction())
{
    // open the dynamic block reference
    BlockReference blockRef = trans.GetObject(blockRefId, OpenMode.ForRead) as BlockReference;
    if (!blockRef.IsDynamicBlock) return;
    DynamicBlockReferencePropertyCollection properties = blockRef.DynamicBlockReferencePropertyCollection;
    for (int i = 0; i < properties.Count; i++)
    {
        DynamicBlockReferenceProperty property = properties[i];
        if (property.PropertyName == "user1")
        {
            property.Value = "a3"; // Change your option here

            // Need code to update the dynamic block after updating a property from block properties table

            break;
        }
    }
    trans.Commit();
}

 

This above code does change the value of a block properties table but does not update the block display itself. Even I run REGEN or close it and open again. So we need the API to update dynamic block geometry entities after changing its custom attributes.

 

-Khoa

 

Moderator
Alexander.Rivilis
Posts: 1,417
Registered: ‎04-09-2008
Message 4 of 9 (2,638 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 02:12 PM in reply to: khoa.ho

Hi, Khoa!

Did you looked to my code? You can see that my code set not only "user1" parameter but also "d1" and "d2" to the correspondent with Block Properties Table values.


Пожалуйста не забывайте про Утвердить в качестве решения! Утвердить в качестве решения и Give Kudos!Баллы
Please remember to Accept Solution! Accept as Solution and Give Kudos!Kudos

Mentor
khoa.ho
Posts: 213
Registered: ‎09-15-2011
Message 5 of 9 (2,633 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 02:39 PM in reply to: Alexander.Rivilis

Hi Alexander,

 

I came up with my answer before your post and only had chance to post after the lunch. I did not see carefully your code and even tried to run it. Anyway, I just gave the idea of the difference between ACAD_ENHANCEDBLOCK and DynamicBlockReferencePropertyCollection. No need to lookup ACAD_ENHANCEDBLOCK extension dictionary unless we want to change the dynamic block definition. Just to use DynamicBlockReferencePropertyCollection if we want to change dynamic block custom attributes.

 

-Khoa

 

Moderator
Alexander.Rivilis
Posts: 1,417
Registered: ‎04-09-2008
Message 6 of 9 (2,629 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 02:49 PM in reply to: khoa.ho

khoa.ho wrote:
...Just to use DynamicBlockReferencePropertyCollection if we want to change dynamic block custom attributes...

Yes. But you have to know not only "user1" value, but also values of "d1" and "d2". And those values are in BlockPropertiesTable.

P.S.: This topic has a "history" in ObjectARX board.


Пожалуйста не забывайте про Утвердить в качестве решения! Утвердить в качестве решения и Give Kudos!Баллы
Please remember to Accept Solution! Accept as Solution and Give Kudos!Kudos

Mentor
khoa.ho
Posts: 213
Registered: ‎09-15-2011
Message 7 of 9 (2,623 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 02:59 PM in reply to: Alexander.Rivilis

Hi Alexander,

 

You are right, I assume the user knows the value to pass. The code is just for demonstration. I don't track ObjectARX forum so I did not know your answer was also there as the poster repeated twice. It's good to know the same resource over there.

 

-Khoa

 

Active Contributor
zhangxinhua789
Posts: 32
Registered: ‎01-29-2013
Message 8 of 9 (2,612 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 04:44 PM in reply to: Alexander.Rivilis

:smileyhappy:you are very great!

Thank you very much!

Active Contributor
zhangxinhua789
Posts: 32
Registered: ‎01-29-2013
Message 9 of 9 (2,609 Views)

Re: how to use a Block Properties Table of a a Dynamic Block using .NET API?

03-07-2013 04:46 PM in reply to: khoa.ho

Thank you very much!

Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.