.NET

Reply
Active Contributor
Andrey_Bushman
Posts: 33
Registered: ‎01-18-2009
Message 1 of 6 (888 Views)

Check is AttributeReference instance of concrete AttributeDefinition?

888 Views, 5 Replies
07-06-2010 07:31 AM

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)... 

 

_________________________________________
AutoCAD .Net Laboratory
*Expert Elite*
norman.yuan
Posts: 946
Registered: ‎04-27-2009
Message 2 of 6 (880 Views)

Re: Check is AttributeReference instance of concrete AttributeDefinition?

07-06-2010 11:08 AM in reply to: Andrey_Bushman

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
    }
}

 

 

Member
lebakram1
Posts: 5
Registered: ‎10-08-2010
Message 3 of 6 (738 Views)

Re: Check is AttributeReference instance of concrete AttributeDefinition?

10-16-2010 06:23 AM 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

Active Contributor
Andrey_Bushman
Posts: 33
Registered: ‎01-18-2009
Message 4 of 6 (713 Views)

Re: Check is AttributeReference instance of concrete AttributeDefinition?

10-17-2010 02:25 AM in reply to: norman.yuan

norman.yuan

Thank you!!!

_________________________________________
AutoCAD .Net Laboratory
Member
lebakram1
Posts: 5
Registered: ‎10-08-2010
Message 5 of 6 (692 Views)

Re: Check is AttributeReference instance of concrete AttributeDefinition?

10-18-2010 06:05 AM 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

*Expert Elite*
norman.yuan
Posts: 946
Registered: ‎04-27-2009
Message 6 of 6 (684 Views)

Re: Check is AttributeReference instance of concrete AttributeDefinition?

10-18-2010 07:04 AM in reply to: Andrey_Bushman

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.

 

You are not logged in.

Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register

Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.

Need installation help?

Start with some of our most frequented solutions to get help installing your software.

Ask the Community