.NET

Reply
Valued Contributor
GrzesiekGP
Posts: 67
Registered: ‎02-03-2012
Message 1 of 13 (488 Views)
Accepted Solution

Get specified attribute from block without loop.

488 Views, 12 Replies
08-09-2012 01:33 PM

Hello!

I know how to get/set attribute within loop at block's AttributeCollection.

 

But I'm wonder if I can set value for specified attribute without loop. Or I always have to iterate on each attribute in block's AttributeCollection?

 

Thanks.

*Expert Elite*
chiefbraincloud
Posts: 752
Registered: ‎02-13-2008
Message 2 of 13 (478 Views)

Re: Get specified attribute from block without loop.

08-09-2012 03:07 PM in reply to: GrzesiekGP

Only if you store the ids somehow, after the first time you find them, or when you create them, but I can't think of very many scenarios where that would be beneficial.

Dave O.                                                                  Sig-Logos32.png
Valued Contributor
GrzesiekGP
Posts: 67
Registered: ‎02-03-2012
Message 3 of 13 (475 Views)

Re: Get specified attribute from block without loop.

08-09-2012 03:19 PM in reply to: chiefbraincloud

Thanks for the reply.

 

I've written own functions to get/set specified attribute (of course with loop using):

 

        private static string GetAttribute(Transaction tr, BlockReference blkRef, string attribute)
        {
            AttributeCollection attCol = blkRef.AttributeCollection;

            foreach (ObjectId attId in attCol)
            {
                AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForWrite);

                if (attRef.Tag.ToUpper() == attribute.ToUpper())
                {
                    return attRef.TextString;
                }
            }

            return string.Empty;
        }

        private static void SetAttribute(Transaction tr, BlockReference blkRef, string attribute, string value)
        {
            AttributeCollection attCol = blkRef.AttributeCollection;

            foreach (ObjectId attId in attCol)
            {
                AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForWrite);

                if (attRef.Tag.ToUpper() == attribute.ToUpper())
                {
                    attRef.UpgradeOpen();
                    attRef.TextString = value;
                    attRef.DowngradeOpen();
                }
            }
        }

 

If someone see some bad code, please let me know :smileyhappy:

*Expert Elite*
chiefbraincloud
Posts: 752
Registered: ‎02-13-2008
Message 4 of 13 (472 Views)

Re: Get specified attribute from block without loop.

08-09-2012 03:36 PM in reply to: GrzesiekGP

I personally don't like passing transactions around, and would prefer to open a new transaction inside these functions, but that is my personal preference.

 

You should, however, be disposing the Attribute References that you open.

 

Otherwise, I have two functions just like these (In VB), and a couple more that overload them where I can pass in a Dictionary(of String, String) to the Set method, and set the values of multiple attributes in the same transaction, or I can get all the tags and values at once by returning the same kind of dictionary from the Get function.

Dave O.                                                                  Sig-Logos32.png
Distinguished Contributor
khoa.ho
Posts: 149
Registered: ‎09-15-2011
Message 5 of 13 (452 Views)

Re: Get specified attribute from block without loop.

08-09-2012 10:13 PM in reply to: GrzesiekGP

AttributeCollection is implemented from the interface ICollection, not from IDictionary. So there is no key-value pair to jump right away to the specified attribute. We expect to have blockReference.AttributeCollection[attributeTagName] = attributeReference, to get a specified attribute without using loop. But AttributeCollection is a .NET collection that is an enumerable list having to deal with iteration loop.

 

We can write code to create an attribute dictionary of a block, then use it to randomly find the attribute (from ObjectId) based on its unique tag:

 

public static Dictionary<string, ObjectId> GetAttributeDictionary(BlockReference blockRef)
{
 var dictionary = new Dictionary<string, ObjectId>();
 using (Transaction tr = blockRef.Database.TransactionManager.StartTransaction())
 {
  AttributeCollection collection = blockRef.AttributeCollection;
  foreach (ObjectId objectId in collection)
  {
   var attribute = (AttributeReference)tr.GetObject(objectId, OpenMode.ForRead);
   dictionary.Add(attribute.Tag, objectId);
  }
  tr.Commit();
 }
 return dictionary;
}

 

public static ObjectId GetAttributeFromTagName(BlockReference blockRef, string attributeTag)
{
 Dictionary<string, ObjectId> dictionary = GetAttributeDictionary(blockRef);
 return dictionary[attributeTag];
}

 

-Khoa

*Expert Elite*
chiefbraincloud
Posts: 752
Registered: ‎02-13-2008
Message 6 of 13 (439 Views)

Re: Get specified attribute from block without loop.

08-09-2012 10:53 PM in reply to: khoa.ho

It is late, and I am a little bleary eyed, and a little tipsy, and I don't mean to be adversarial, or controversial, but that does not help to prevent the iteration of the attribute collection.  It might be the underlying code for storing the IDs as I had originally proposed, but as written it does not store the IDs, it just iterates the collection every time the wrapper function is called, so it saves you nothing.

 

I've got to get to bed, and trying to read C# code right now is making me dizzy.  I'll look at it again tommorrow and see if I feel differently about it.

Dave O.                                                                  Sig-Logos32.png
*Expert Elite*
_gile
Posts: 2,071
Registered: ‎04-29-2006
Message 7 of 13 (436 Views)

Re: Get specified attribute from block without loop.

08-09-2012 11:19 PM in reply to: chiefbraincloud

Hi,

 

chiefbraincloud,

I too don't like passing transactions around but I won't open a new while a TopTransaction is running.

Disposing the Attribute References that you open is unnecessary because it's opened with the transaction which will dispose it for you.

 

By my side, I use some extension methods with Dictionary<string, string>.

 

Here's an extract:

    public static class AttributeExtensions
    {
        public static IEnumerable<AttributeReference> GetAttributes(this AttributeCollection attribs)
        {
            foreach (ObjectId id in attribs)
            {
                yield return (AttributeReference)id.GetObject(OpenMode.ForRead, false, false);
            }
        }

        public static Dictionary<string, string> GetAttributesValues(this BlockReference br)
        {
            return br.AttributeCollection
                .GetAttributes()
                .ToDictionary(att => att.Tag, att => att.TextString);
        }

        public static void SetAttributesValues(this BlockReference br, Dictionary<string, string> atts)
        {
            foreach (AttributeReference attRef in br.AttributeCollection.GetAttributes())
            {
                if (atts.ContainsKey(attRef.Tag))
                {
                    attRef.UpgradeOpen();
                    attRef.TextString = atts[attRef.Tag];
                }
            }
        }
    }

 

Gilles Chanteau
Valued Contributor
GrzesiekGP
Posts: 67
Registered: ‎02-03-2012
Message 8 of 13 (424 Views)

Re: Get specified attribute from block without loop.

08-10-2012 02:51 AM in reply to: GrzesiekGP

Excelent idea with dictionary use :smileyhappy:

 

Thanks mate!

Distinguished Contributor
khoa.ho
Posts: 149
Registered: ‎09-15-2011
Message 9 of 13 (406 Views)

Re: Get specified attribute from block without loop.

08-10-2012 06:36 AM in reply to: chiefbraincloud

Definitely we call the method GetAttributeDictionary() only one time, store in a variable, and use it many times based on specified attribute tag names. The second method (GetAttributeFromTagName) just shows how to find an attribute in the dictionary.

 

ObjectId is more generic to present an attribute reference. Then we can call GetObject() method to get or update attribute values. AttributeCollection is also a collection of ObjectIds.

 

-Khoa

*Expert Elite*
chiefbraincloud
Posts: 752
Registered: ‎02-13-2008
Message 10 of 13 (396 Views)

Re: Get specified attribute from block without loop.

08-10-2012 08:07 AM in reply to: _gile

gile

 

I also try not to have nested transactions, and I should have also mentioned I don't like passing around open objects, either.  I always pass ObjectIds and open them in the function that is doing the work.

 

As I mentioned above, I also have two methods that use String, String dictionaries to get or set attributes.  I love dictionaries, but it is not feasable for me to create a String, ObjectId dictionary and leave it memory resident to use later.  I just don't think that is a good idea at all.  My code deals with far too many blocks and attributes to load up the memory like that.

Dave O.                                                                  Sig-Logos32.png

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