Painting properties between dynamic AutoCAD blocks using .NET

In the last post we looked at some code that essentially dumped out the dynamic properties of dynamic blocks to the command-line. In this post we take it a step further and capture the properties from one dynamic block reference and attempt to apply them to another.

We're going to apply slightly different logic, depending on the situation...

If the block references refer to the same dynamic block definition (i.e. their DynamicBlockTableRecord property contains the same ObjectId) then we'll assume they have the same dynamic properties in the same order. So we'll go through and attempt to copy the property value from the first to the second. This may be a flawed approach, I don't know enough to say whether there are situations where dynamic blocks might have different sets of properties or properties in a different order... if it proves to be a problem, it'd be a simple matter to remove this clause and rely on the second approach for all dynamic block references.

If the block references refer to different dynamic block definitions (i.e. their DynamicBlockTableRecord property contains different ObjectIds) then we use a slightly more elaborate approach: we go through the dynamic properties of the "source" dynamic block reference and store them in a dictionary. We then go through the dynamic properties of the "target" dynamic block reference, and if we find a value in the list we then attempt to apply it to this reference. In this way we should be able to paint properties across blocks - as long as they have the same name - even if they don't have the same overall make-up.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

using System.Collections.Generic;

 

namespace DynamicBlocks2

{

  public class Commands

  {

    [CommandMethod("ADBP")]

    static public void ApplyDynamicBlockProps()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      // Select the source and target block references

 

      PromptEntityOptions peo =

        new PromptEntityOptions(

          "\nSelect source 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;

 

      ObjectId sourceId = per.ObjectId;

 

      peo.Message =

        "\nSelect target dynamic block reference: ";

      per = ed.GetEntity(peo);

 

      if (per.Status != PromptStatus.OK)

        return;

 

      ObjectId targetId = per.ObjectId;

 

      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // Open our block references: the source (br1)

        // for read and the target (br2) for write

 

        BlockReference br1 =

          (BlockReference)tr.GetObject(

            sourceId,

            OpenMode.ForRead

          );

 

        BlockReference br2 =

          (BlockReference)tr.GetObject(

            targetId,

            OpenMode.ForWrite

          );

 

        // They must both be dynamic block references

 

        if (br1 != null && br1.IsDynamicBlock &&

            br2 != null && br2.IsDynamicBlock)

        {

          if (br1.DynamicBlockTableRecord ==

              br2.DynamicBlockTableRecord)

          {

            // They use the same block definition - let's assume

            // the properties are in the same order

 

 
;          
DynamicBlockReferencePropertyCollection pc1 =

              br1.DynamicBlockReferencePropertyCollection;

 

            DynamicBlockReferencePropertyCollection pc2 =

              br2.DynamicBlockReferencePropertyCollection;

 

            if (pc1.Count == pc2.Count)

            {

              for (int i = 0; i < pc1.Count; i++)

              {

                // Get each property. If they have the same

                // name and are not read-only, attempt to

                // copy the value from the source (prop1)

                // to the target (prop2)

 

                DynamicBlockReferenceProperty prop1 = pc1[i],

                                              prop2 = pc2[i];

                if (prop1.PropertyName == prop2.PropertyName &&

                    !prop1.ReadOnly && !prop2.ReadOnly)

                {

                  prop2.Value = prop1.Value;

                }

              }

            }

          }

          else

          {

            // If the block references refer to different

            // dynamic block definitions, let's collect the

            // properties for the first in a dictionary and

            // attempt to apply them to the second

 

            DynamicBlockReferencePropertyCollection pc1 =

              br1.DynamicBlockReferencePropertyCollection;

 

            // Create and populate our dictionary

 

            D
ictionary
<string, DynamicBlockReferenceProperty> dict =

              new

              Dictionary<string, DynamicBlockReferenceProperty>();

 

            foreach (DynamicBlockReferenceProperty prop in pc1)

            {

              if (!prop.ReadOnly &&

                  !dict.ContainsKey(prop.PropertyName))

                dict.Add(prop.PropertyName, prop);

            }

 

            // Try to copy them to the target block reference's

            // dynamic properties

 

            DynamicBlockReferencePropertyCollection pc2 =

              br2.DynamicBlockReferencePropertyCollection;

 

            foreach (DynamicBlockReferenceProperty prop2 in pc2)

            {

              if (!prop2.ReadOnly &&

                  dict.ContainsKey(prop2.PropertyName))

              {

                try

                {

                  DynamicBlockReferenceProperty prop1;

                  if (dict.TryGetValue(

                        prop2.PropertyName, out prop1

                    )

                  )

                  {

                    if (prop2.PropertyTypeCode ==

                        prop1.PropertyTypeCode)

                    {

   
60;                  prop2.Value = prop1.Value;

                    }

                  }

                }

                // Expand if you want to diagnose specific issues

                catch { }

              }

            }

          }

        }

        else

        {

          ed.WriteMessage(

            "\nYou need to select two dynamic bock references."

          );

        }

        tr.Commit();

      }

    }

  }

}

Let's see what happens when we put our ADBP command through its paces. Here's our initial state - we have two differently-sized instances of the same dynamic block, plus one instance of a different dynamic block (which shares parameters - the left-hand block is a "Hex Socket Bolt (Side)" while the right-hand block is a "Hex Nut" - both these blocks are available in the "Mechanical - Metric.dwg" sample file in the Samples\Dynamic Blocks folder of your AutoCAD installation).

Dynamic block references

Here's where we are when we run our ADBP command and select the block reference at the top followed by the block reference at the bottom-left:

Dynamic block references - after paint from top to bottom elevation view 

So we see it works on references of the same dynamic block definition. Now let's try it, selecting one of the left-hand elevation views on the bolt, followed by the plan view of the nut on the right:

Dynamic block references - after paint from elevation to plan view

Because they share a dynamic property ("Size", which went from "M10" to "M14"), we were able to "paint" from one to the other.

With AutoCAD 2010 you'll be able to create constraints between geometry - which is a much simpler and more powerful approach - but what we've seen in this post should be of use to people working with dynamic blocks today.

By the way - for those of you with ADN website access - I used this DevNote as inspiration for how to modify properties in a dynamic block reference: How to programmatically insert a dynamic block with attributes containing dynamic parameters? (requires login.) Thanks to Fernando for pointing me to it (at that point in my research I had not quite gotten as far as checking the ADN website... ahem), as well as for suggesting this topic in the first place.

7 responses to “Painting properties between dynamic AutoCAD blocks using .NET”

  1. Darcy buss Neto Avatar
    Darcy buss Neto

    Hello KEAN WALMSLEY,

    I need open drawing on autocad.

    Ex.

    My drawing1 IS open and this drawing has a list has a link with drawing2.

    With i double click on list ( windows forms ) open the link ( drawing 2 )

    Do you have how resolve this problem?

    "Sorry English"...

  2. Kean Walmsley Avatar

    Please post future questions to the AutoCAD .NET Discussion Group, unless they relate to a specific post.

    It sounds as though you probably want to send the -OPEN command to open Drawing2. I suggest checking out SendStringToExecute() as shown in this post .

    Kean

  3. Wallace Kunin Avatar

    I am having an issue where I insert a dynamic block into a drawing after programmatically changing one of its properties. The block has scaled accordingly but now the grips no longer scale the block and changing the property in the properties palette does nothing more than move the grips to where they should be but the block still stays the same. This only happens when they property is changed programmatically. Any ideas how to fix this?

  4. Wallace Kunin Avatar

    To follow up on this issue, when i move the block by its base point, AutoCAD shows the preview image(I'm guessing they use a jig) in the size that the block is supposed to be according to the grips and the property but when I click again to place the block in the new location, it stays the incorrect size.

  5. Kean Walmsley Avatar

    There have been a couple of issues related to programmatic modification of dynamic blocks (that I've seen).

    The case I used was quite simple - you may hit issues (that are beyond my experience to fix) if your blocks are more complex. If you hit issues I suggest posting to the ADN website (if you're a member) or otherwise to the AutoCAD .NET discussion group.

    Kean

  6. Wallace Kunin Avatar

    To follow up on this I have the solution, which may help people in the future. The dynamic properties of a block reference can only be edited after the block reference has been appended to model space to avoid causing errors. I edited the property for the jig then created a new blockreference with the point selected from the jig and added that to model space, then edited its property accordingly.

  7. Kean, very good job !!!

Leave a Reply to Andres Beja Cancel reply

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