.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Check is AttributeReference instance of concrete AttributeDefinition?

5 REPLIES 5
Reply
Message 1 of 6
Andrey_Bushman
1307 Views, 5 Replies

Check is AttributeReference instance of concrete AttributeDefinition?

Hello all.

I have next instances:


1. BlockTableRecord

2. BlockReference

3. AttributeDefinition

4. AttributeReference


How can I check is AttributeReference instance of concrete AttributeDefinition?


I look next properties of AttributeReference object: ObjectId, OwnerId, BlockId, but it's not help me (it's ID's for other objects)... 

 

5 REPLIES 5
Message 2 of 6

Let me see if I understand your question correctly: you want to determine an attribute reference found in a block reference is created based on which attribute definition defined in the BlockTableRecord. If that is the question, then read on.

 

AttributeReference in a BlockReference has no "hard link" to an AttributeDefinition on which it is based. AttributeDefinition is only served as a template when an AttributeReference is created. After being created, it has no tie to any AttributeDefinition.

 

One might think AttributeReference.Tag can be used for looking up which AttributeDefinition in the BlockTableRecord is used to create the AttributeReference. Well, AttributeReference's Tag property is Read/Write-able, you can change it to anything (to be different from the AttributeDefinition it is based) with code.

 

You can also erase an AttributeReference from the BlockReference, so that even the block definition contains x number of attribute defined, but the block reference can y number of AttrbuteReferences in it.

 

Furthur more, you can add AttributeReference to a block reference without AttributeDefinition.

 

There relationship between AttributeDefinition and AttributeReference is different from block definition (BlockTableRecord) and block reference (BlockReference)

 

Therefore, there is no relaible way for you to trace back to AttributeDefinition from a give AttributeReference.

 

Below is some quick code to show what I described (assume you have a drawing, in which you have a block with 3 attributes defined, and you have that block inserted. See attached picture)

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.Geometry;

[assembly: CommandClass(typeof(AttributeInBlock.MyCommand))]

namespace AttributeInBlock
{
    public class MyCommand 
    {

        [CommandMethod("AttrTest")]
        public static void AttrTest()
        {
            Document dwg = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = dwg.Editor;

            ObjectId blkRefID = PickBlockReference(ed);

            if (blkRefID == ObjectId.Null) return;

            ChangeAttributeInBlockReference(dwg,blkRefID);

            ed.WriteMessage("\nMyCommand executed.");
        }

        #region private methods

        private static ObjectId PickBlockReference(Editor ed)
        {
            PromptEntityOptions opt = new PromptEntityOptions("\nPick a block reference: ");
            opt.SetRejectMessage("Invalid pick - not a block refernece.");
            opt.AddAllowedClass(typeof(BlockReference), true);

            PromptEntityResult res = ed.GetEntity(opt);

            if (res.Status == PromptStatus.OK)
            {
                return res.ObjectId;
            }
            else
            {
                return ObjectId.Null;
            }
        }

        private static void ChangeAttributeInBlockReference(Document dwg, ObjectId brefID)
        {
            using (Transaction tran = dwg.Database.TransactionManager.StartTransaction())
            {
                BlockReference blkRef = (BlockReference)tran.GetObject(brefID, OpenMode.ForWrite);

                //Rename attribute
                foreach (ObjectId att in blkRef.AttributeCollection)
                {
                    AttributeReference attRef = (AttributeReference)tran.GetObject(att, OpenMode.ForWrite);

                    if (attRef.Tag.ToUpper() == "AAA") attRef.Tag = "XXX";
                    if (attRef.Tag.ToUpper() == "BBB") attRef.Tag = "YYY";
                    if (attRef.Tag.ToUpper() == "CCC") attRef.Tag = "ZZZ"; 
                }

                //Erase an attribute reference
                foreach (ObjectId att in blkRef.AttributeCollection)
                {
                    AttributeReference attRef = (AttributeReference)tran.GetObject(att, OpenMode.ForWrite);

                    if (attRef.Tag.ToUpper() == "ZZZ")
                    {
                        attRef.Erase();
                        break;
                    }
                }

                //Create a new attributereference (without referencing an attribute definition
                AttributeReference attr = new AttributeReference(
                    new Point3d(0.0, 0.0, 0.0), "12345", "DDD", dwg.Database.Textstyle);
                attr.TransformBy(Matrix3d.Displacement(new Vector3d(blkRef.Position.X,blkRef.Position.Y,blkRef.Position.Z)));
                
                //Add the attribute to the blockreference
                blkRef.AttributeCollection.AppendAttribute(attr);

                tran.AddNewlyCreatedDBObject(attr, true);

                tran.Commit();
            }
        }

        #endregion
    }
}

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 6
lebakram1
in reply to: Andrey_Bushman

Hi Norman,

 

thank you for your excellent explanation, this should indeed be part of the ARX doc.

 

I have the following question (which I already googled without success):

How to reorder the Attributereferences ?

 

ACAD itself is doing it with the BATTMAN command.

In .NET we have the BlockReference.AttributeCollection but it is read-only. So what can we do ?

Read all AttributeReferences into a temporary array, sort them, remove all ARs from BR, append sorted ARs.

Is that the best way ? Does anyone have a code example ?

 

Mark

Message 4 of 6

norman.yuan

Thank you!!!

Message 5 of 6
lebakram1
in reply to: Andrey_Bushman

Hi Norman,

 

I just discovered a nasty problem: AttributeReferences without AttributeDefinitions will show up in the Property Palette only when AR.visible=true.

I want to set AR.Visible to false because I do not want to show the attributes in the dwg only in the PP.

 

Any Idea ?

Mark

Message 6 of 6

Well, being able to create AttributeReference without corresponding AttributeDefinition doe not mean it is a good practice to do so. Maybe in some specific situation, one has to do it, so, be it with the consequence it may result in. In my previous post, I just point out that it is possible and meant to say that one may not be able to trace it back to an AttributeDefinistion from an AttributeReference.

 

There is also other oddity that may be overlooked by ordinary Acad programmer with block attribute. For example, we often see code use Attribute Tag to identif AttributeReference. But one has to realize that a block may have more than one AttributeDefinition with the same tag, while AttributeReferences created based on these AttributeDefinition could have different value (TextString), even their Tag properties are the same.

 

As for your previous question on "ordering AttributeReferences", I see the "BATTMAN" sets the order of AttributeReference being added to a block, should the blockreference is inserted by user. It may be useful for user to entering attribute value manually: the prompt would be in a logic order so that is easily understandable. If you use code to create blockreference with attribute, the attribute reference can be added to the blockreference in any order. I am not sure I'd bother to care what order the attribute is prompted/inserted. But be honest, I do not see a way other than you described: retrieving the attribute data and stored somewhere, erase all attributereferences, and re-append the attributereferences back in desired order.

 

Norman Yuan

Drive CAD With Code

EESignature

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost