Accessing the properties of a dynamic AutoCAD block using .NET

This is one of those funny scenarios... I was just thinking about what to do for my next post - whether to dive into some new features of AutoCAD 2010 (which I will do soon, I promise! 🙂 or whether to choose something from my ever-increasing to-do list, when I received two emails.

One was from our old friend Fernando Malard, suggesting a topic for a blog post, and the other was from Philippe Leefsma, a member of our DevTech team in Europe, in response to an ADN members question. It provided some code that could eventually form the basis for a response to Fernando's question. Coincidence? Maybe. Am I one to ignore serendipity at work (or to look a gift horse in the mouth)? No!

So, here's Fernando's question:

Just would suggest a new topic for your Blog. An article explaining how to insert a dynamic block and modifying its dynamic properties like point, rotation, dimension. This is something I'm currently working on .NET and I think it would be a very interesting topic to evolve.

Philippe's code is a little different - it shows how to retrieve and display the "dynamic" properties of a dynamic block read in from an external file - but it was a great start for my first step towards Fernando's goal, which was simply to access the dynamic properties for a block selected by the user.

Here's the C# code I based on Philippe's:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

 

namespace DynamicBlocks

{

  public class Commands

  {

    [CommandMethod("DBP")]

    static public void DynamicBlockProps()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      PromptStringOptions pso =

        new PromptStringOptions(

          "\nEnter dynamic block name or enter to select: "

        );

 

      pso.AllowSpaces = true;

      PromptResult pr = ed.GetString(pso);

 

      if (pr.Status != PromptStatus.OK)

        return;

 

      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        BlockReference br = null;

 

        // If a null string was entered allow entity selection

 

        if (pr.StringResult == "")

        {

          // Select a block reference

 

          PromptEntityOptions peo =

            new PromptEntityOptions(

              "\nSelect dynamic block reference: "

            );

 

          peo.SetRejectMessage("\nEntity is not a block.");

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

 

          PromptEntityResult per =

            ed.GetEntity(peo);

 

          if (per.Status != PromptStatus.OK)

            return;

 

          // Access the selected block reference

 

          br =

            tr.GetObject(

              per.ObjectId,

              OpenMode.ForRead

            ) as BlockReference;

        }

        else

        {

          // Otherwise we look up the block by name

 

          BlockTable bt =

            tr.GetObject(

              db.BlockTableId,

              OpenMode.ForRead) as BlockTable;

 

          if (!bt.Has(pr.StringResult))

          {

            ed.WriteMessage(

              "\nBlock \"" + pr.StringResult + "\" does not exist."

            );

            return;

          }

 

          // Create a new block reference referring to the block

 

          br =

            new BlockReference(

              new Point3d(),

              bt[pr.StringResult]

            );

        }

 

        BlockTableRecord btr =

          (BlockTableRecord)tr.GetObject(

            br.DynamicBlockTableRecord,

            OpenMode.ForRead

          );

 

        // Call our function to display the block properties

 

        DisplayDynBlockProperties(ed, br, btr.Name);

 

        // Committing is cheaper than aborting

 

        tr.Commit();

      }

    }

 

    private static void DisplayDynBlockProperties(

      Editor ed, BlockReference br, string name

    )

    {

      // Only continue is we have a valid dynamic block

 

      if (br != null && br.IsDynamicBlock)

      {

        ed.WriteMessage(

          "\nDynamic properties for \"{0}\"\n",

          name

        );

 

        // Get the dynamic block's property collection

 

        DynamicBlockReferencePropertyCollection pc =

          br.DynamicBlockReferencePropertyCollection;

 

        // Loop through, getting the info for each property

 

        foreach (DynamicBlockReferenceProperty prop in pc)

        {

          // Start with the property name, type and description

 

          ed.WriteMessage(

            "\nProperty: \"{0}\" : {1}",

            prop.PropertyName,

            prop.UnitsType

          );

 

          if (prop.Description != "")

            ed.WriteMessage(

              "\n  Description: {0}",

              prop.Description

            );

 

          // Is it read-only?

 

          if (prop.ReadOnly)

            ed.WriteMessage(" (Read Only)");

 

          // Get the allowed values, if it's constrained

 

          bool first = true;

 

          foreach (object value in prop.GetAllowedValues())

          {

            ed.WriteMessage(

              (first ? "\n  Allowed values: [" : ", ")

            );

            ed.WriteMessage("\"{0}\"", value);

 

            first = false;

          }

          if (!first)

            ed.WriteMessage("]");

 

          // And finally the current value

 

          ed.WriteMessage(

            "\n  Current value: \"{0}\"\n",

            prop.Value

          );

        }

      }

    }

  }

}

Here's what happens when we run the DBP command, selecting the "Hex Socket Bolt (Side) - Metric" block from the "Mechanical - Metric.dwg" file in the Samples\Dynamic Blocks folder of your AutoCAD installation.

Command: DBP

Enter dynamic block name or enter to select:

Select dynamic block reference:

 

Dynamic properties for "Hex Socket Bolt (Side) - Metric"

 

Property: "d1" : Distance

  Allowed values: ["3", "4", "5", "6", "8", "10", "12", "14", "16", "20", "24",

"27", "30", "36"]

  Current value: "14"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(97.714,-5,0)"

 

Property: "b" : Distance

  Allowed values: ["18", "20", "22", "24", "28", "32", "36", "40", "44", "52",

"57", "60", "65", "66", "72", "73", "84", "85"]

  Current value: "40"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(100,-3.5,0)"

 

Property: "k" : Distance

  Allowed values: ["3", "4", "5", "6", "8", "10", "12", "14", "16", "20", "24",

"27", "30", "36"]

  Current value: "14"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(5.64204767561892E-15,-7,0)"

 

Property: "d2" : Distance

  Allowed values: ["5.5", "7", "8.5", "10", "13", "16", "18", "21", "24", "30",

"36", "40", "45", "54"]

  Current value: "21"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(3.5527136788005E-15,-8,0)"

 

Property: "Size" : NoUnits

  Allowed values: ["M3", "M4", "M5", "M6", "M8", "M10", "M12", "M14"]

  Current value: "M14"

 

Property: "Visibility" : NoUnits

  Allowed values: ["M3", "M4", "M5", "M6", "M8", "M10", "M12", "M14"]

  Current value: "M14"

 

Property: "Length (M3)" : Distance

  Description: Set the bolt length

  Allowed values: ["25", "30", "35", "40", "45", "50", "60"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(0,0,0)"

 

Property: "Length (M4)" : Distance

  Description: Set the bolt length

  Allowed values: ["30", "35", "40", "45", "50", "60", "70", "80"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(0,0,0)"

 

Property: "Length (M5)" : Distance

  Description: Set the bolt length

  Allowed values: ["30", "35", "40", "45", "50", "55", "60", "70", "80", "90",

"100"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(0,0,0)"

 

Property: "Length (M6)" : Distance

  Description: Set the bolt length

  Allowed values: ["35", "40", "45", "50", "55", "60", "65", "70", "75", "80",

"90", "100", "110", "120"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(2.25597318603832E-14,0,0)"

 

Property: "Length (M8)" : Distance

  Description: Set the bolt length

  Allowed values: ["40", "45", "50", "55", "60", "65", "70", "75", "80", "85",

"90", "100", "110", "120", "130", "140", "150", "160", "180", "200"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(2.25597318603832E-14,0,0)"

 

Property: "Length (M10)" : Distance

  Description: Set the bolt length

  Allowed values: ["45", "50", "55", "60", "65", "70", "75", "80", "85", "90",

"100", "110", "120", "130", "140", "150", "160", "180", "200"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(2.25597318603832E-14,0,0)"

 

Property: "Length (M12)" : Distance

  Description: Set the bolt length

  Allowed values: ["55", "60", "65", "70", "75", "80", "85", "90", "100",

"110", "120", "130", "140", "150", "160", "180", "200"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(2.25597318603832E-14,0,0)"

 

Property: "Length (M14)" : Distance

  Description: Set the bolt length

  Allowed values: ["60", "65", "70", "75", "80", "90", "100", "110", "120",

"130", "140", "150", "160"]

  Current value: "100"

 

Property: "Origin" : NoUnits (Read Only)

  Current value: "(2.25597318603832E-14,0,0)"

Many of the properties are actually 0, but have ended up being printed as a very small number... it would be simple enough to check these against a tolerance rather than trusting them to be understood as being zero.

OK, that's a good enough start for today. In the next post we'll address the need to capture dynamic properties from an inserted dynamic block and copy them across to another, already-inserted dynamic block. A bit like a "property painter" for dynamic blocks. (If you're thinking that this doesn't sound quite like what Fernando originally asked for, then you'd be quite right. We exchanged a few emails, and I then opted for a "property painter" approach to address the problem.)

Thanks for the inspiration, Fernando and Philippe! 🙂

25 responses to “Accessing the properties of a dynamic AutoCAD block using .NET”

  1. What all this Origin's means?
    How to uniquely identify them?

  2. Kean, thanks for the example. I'd like to know if there is .NET API that allows to modify the definition, particularly those dynamic properties) of a dynamic block.

  3. Kean Walmsley Avatar

    quiz -

    From what I can tell each linear parameter (of type "Distance" in the output) has its own read-only Origin property. So you can identify it based on relative position in the list (or the fact it's read-only). There may be other situations where you might get repeated property names in the list, but this is the main time I've experienced it thus far (although I admittedly haven't worked very much with dynamic blocks, myself).

    Kelie -

    Unfortunately there is currently no API exposed for manipulating dynamic block definitions - only dynamic block references.

    Regards,

    Kean

  4. Kélcyo Pereira Avatar
    Kélcyo Pereira

    Hello Kean,
    This very important topic on dynamic blocks, we deal more about it.
    Enjoying the ride on dynamic things, like taking a doubt. I was watching some screencast of PDC, and saw the new features in WF 4.0. I ask you, you can use Workflow in Autocad? Would have an example in the future? I will be very grateful if possible.
    Regards.

  5. Kean Walmsley Avatar

    Hi Kélcyo,

    I'm sure you can use WF in AutoCAD, I've just never tried. A more urgent topic for me is to spend some serious time on WPF (as we're using it directly in AutoCAD for our Ribbon implementation), but I'll add WF to my list of things to look at, at some point.

    Regards,

    Kean

  6. Hi,

    I'm really new at AutoCAD this Framework (3 days old) and i have a question that maybe doesn't make much sense, but here it goes:

    How can i get the BlockReference from an Entity?

    Because i'm developing a Batch Process that between many things, needs some specific properties that i can only find in the BlockReference class, such as "Rotation".

    Thanks
    Pedro Abreu

  7. Kean Walmsley Avatar

    Hi Pedro,

    I suggest working through some of the introductory material on the AutoCAD Developer Center (the AutoCAD .NET Labs should help).

    Regards,

    Kean

  8. Hi Kean,

    In a dynamic block, is it possible to show different color to same entity in different sate? (Without automation)
    Ex. State Blue will show blue color, State Green will show green color to same entity.

    Thanks,

    Pradeep

  9. Hi Pradeep,

    I don't know, but then I'm far from being an expert on the capabilities of dynamic blocks.

    I suggest you submit your question via the ADN website (if you're a member) or one of our online discussion groups (which is - in any case - advisable when asking a question that's not specifically related to a post).

    Regards,

    Kean

  10. Thanks Kean...

  11. Hi Kean,
    many thanks for this example.
    Is there any way to define the value of a dynamic property.
    I did it this way: prop.value = "1234";
    When I do so autocad crashed with no error-messages.

    thanks for your help
    Jürgen

  12. Hi Jürgen,

    Have you debugged through and checked what type prop.Value is? The above code uses quotation marks to delimit the value - it doesn't necessarily mean the value is always a string.

    Regards,

    Kean

  13. Hi Kean. I have written a short addin that makes the following:

    Reads the first column looking for a name.
    If that names is one of the dynamic block names already present in the drawing, makes a reference of it (instance)
    Then reads the following columns searching for parameter names and values, and if finds the same paramaeter name in the dynamic block, it applies it the read value.

    My dynamic blocks definitions contain parametric relationships and restrictions.

    My problem comes when I run the code. If the number of parameters to modify or update on each block is small the code runs ok, but when I try to update around 20 parameters, autocad crashes, like it needed more memory or resources.
    Could you give me any tips on how to use transactions so my blocks get added to the drawing and the updated without consuming too many resources...

    Thanks!

    My problem is that for

  14. Kean Walmsley Avatar

    Hi Roberto,

    Sorry - I have neither the time nor the expertise to help you with this issue.

    Please submit your question to the ADN team, if you're a member, or otherwise the AutoCAD .NET Discussion Group.

    Regards,

    Kean

  15. Hi Kean,

    Thanks for the awesome web site.

    Do you know if it is possible to modify a Dynamic Block with .Net by setting a value in its Block Properties Table? I'm getting erratic results when editing each property individually to the values that make up the Table Entry.

  16. Hi Dale,

    Does this follow-on post help, at all?

    keanw.com/2009/03/painting-properties-between-dynamic-autocad-blocks-using-net.html

    Regards,

    Kean

  17. Gerrit van Diepen Avatar
    Gerrit van Diepen

    Hi Kean,

    Is it possible to get the rotation angle of an inserted dynamic block.
    If I list the properties of an dynamic block reference by .Net the 'Rotation' property is allways 0

    I Wonder wat I am doing wrong.

    Regards,

    Gerrit

  18. Gerrit van Diepen Avatar
    Gerrit van Diepen

    Sorry for this question.
    Because the Dynamic block has an Angular action and the block was rotated by this angular action the Rotation property stays 0.
    Only after using the rotate command the Rotation property is changed.
    So, to get the active rotation you have to get the Rotation property and the Angular action value.

  19. Thanks for posting what worked for you, Gerrit!

    Happy New Year,

    Kean

  20. How do you go about printing out all the geometric constraints of a given drawing? I think "Assoc2dConstraintGroup" is the right place to look but I am not sure where those relationships are buried. I am interested in reading coincidence constraints between two entities in a drawing..

  21. I have looked at this example, It works well for creation of coincident constraints for example,but how do I read the coincident constraints..I get how information about dimensional constraints can be accessed through the block reference but I don't know where geometric constraint information is being stored. Given a drawing, I want to be able to list out pairs of block references that are bound together by a coincident constraint .thank you for your time.

  22. If it's not covered by the sample then I suggest posting your request to the AutoCAD .NET Discussion Group (or directly to ADN, if you're a member).

    Kean

  23. Hi Kean,
    I must came back to this point after so much years.
    In a new project I 've got the same problem and yes I checked the type of prop.Value. It is object{double} and I put in a double-value, declared a double or object. Thats makes no differents. The error is eInvalidInput.
    Philippe Leefsma thinks it doesnt work in C# and gave me an example in C++. But C++ is not that think for me.
    My question to you is: Do you got an idea to fix this problem? That would be very kind of you.

    Best Regards Jürgen.

  24. Hi Jürgen,

    Unfortunately not. This code was always Philippe's, so I don't have any deeper insights to share. I can't say whether what you want to do is possible in C#.

    Best regards,

    Kean

Leave a Reply to Insia Iftiqhar Cancel reply

Your email address will not be published. Required fields are marked *