1

Is it possible to change the Constant property of an AttributeReference ? (the property IsConstant is readonly)

Florian
  • 4,507
  • 10
  • 53
  • 73
  • Why have you tagged `autocad` and `objectarx`? Do you have a specific problem you're trying to solve by changing attribute values (which isn't possible as it's part of the class's metadata)? If so then explain that problem as there may be another solution. – D Stanley Aug 25 '15 at 12:56

2 Answers2

2

I don't know about objectarx, but in .Net (since you stated c#), try this:

        Database currentDB = Application.DocumentManager.MdiActiveDocument.Database;
        using (Transaction transaction = currentDB.TransactionManager.StartTransaction())
        {
            BlockTable blockTable = (BlockTable)transaction.GetObject(currentDB.BlockTableId, OpenMode.ForRead);

            //Create the block if it doesn't exist
            if (!blockTable.Has("MyBlock"))
            {
                using (BlockTableRecord myBlock = new BlockTableRecord())
                {
                    myBlock.Name = "MyBlock";
                    myBlock.Origin = Point3d.Origin;

                    //You can add geometry here, but I'm just going to create the attribute
                    using (AttributeDefinition attribute = new AttributeDefinition())
                    {
                        attribute.Position = Point3d.Origin;
                        attribute.Tag = "Constant";
                        attribute.Prompt = "Enter value: ";
                        attribute.TextString = "My value";
                        attribute.Height = 0.5;
                        attribute.Justify = AttachmentPoint.BottomLeft;
                        attribute.Constant = true;

                        myBlock.AppendEntity(attribute);

                        //add to the block table
                        blockTable.UpgradeOpen();
                        blockTable.Add(myBlock);
                        transaction.AddNewlyCreatedDBObject(myBlock, true);

                    }

                }

                transaction.Commit();
            }
        }

Edit: I just realized you also said AttributeReference and not AttributeDefinition. Without verifying for sure, I think the reference cannot be modified directly since the value is constant. Because of this, you'll have to update the block's definition in the BlockTableRecord, same basic process once you've got it.

Here's the code for updating:

       Database currentDB = Application.DocumentManager.MdiActiveDocument.Database;
        using (Transaction transaction = currentDB.TransactionManager.StartTransaction())
        {
            BlockTable blockTable = (BlockTable)transaction.GetObject(currentDB.BlockTableId, OpenMode.ForRead);


            //Create the block if it doesn't exist
            if (blockTable.Has("MyBlock"))
            {
                //Get the block
                ObjectId myBlockID = blockTable["MyBlock"];
                BlockTableRecord myBlock = (BlockTableRecord)transaction.GetObject(myBlockID, OpenMode.ForRead);

                //iterate through objects and update the attribute definition
                if (myBlock.HasAttributeDefinitions)
                {
                    foreach (ObjectId oid in myBlock)
                    {
                        DBObject dbObject = transaction.GetObject(oid, OpenMode.ForRead);
                        if (dbObject is AttributeDefinition)
                        {
                            AttributeDefinition attribute = (AttributeDefinition)dbObject;

                            attribute.UpgradeOpen();

                            attribute.TextString = "NewValue";
                            attribute.Constant = true;
                        }
                    }
                }

                //Remember... BlockRerefences are glorified pointers to the BlockTableRecord that defines them
                //so let's get all block references associated to it and update them

                foreach (ObjectId oid in myBlock.GetBlockReferenceIds(false, true))
                {
                    BlockReference blockReference = (BlockReference)transaction.GetObject(oid, OpenMode.ForWrite);
                    blockReference.RecordGraphicsModified(true);
                }

                transaction.Commit();
            }
        }
bjhuffine
  • 924
  • 1
  • 11
  • 23
  • 3
    bjhuffine is correct. Constant attributes need to be modified in the BlockTableRecord, not in the reference. They're basically an easy to find text object. – Miiir Aug 25 '15 at 14:49
  • Sorry to answer so lately :-/ I'm trying to implement your solution but myblock.HasAttributeDefinitions returns false... Should I recreate AttributeDefinitions from AttributeReferences (and set AttributeDefinition.Constant to true at this moment ?) Regards, – Florian Sep 02 '15 at 10:03
  • @Florian: Not sure what you have, but it works for me. To see this in action, try this.... 1.) copy each code example into it's own command. Call the first command "CreateBlock", call the second "UpdateBlock". 2.) run the program in debug mode and netload. 3.) call "CreateBlock"... this should create the BlockTableRecord used to insert into the drawing. 4.) The the AutoCAD "Insert" command and insert "MyBlock" into the drawing. You can insert it many times if you want. 5.) Call the "UpdateBlock" command and you'll see the constant textstring value change in the drawing. – bjhuffine Sep 02 '15 at 11:22
  • 1
    @Florian: Oh yeah, I'm also using 4.5 vers framework and AutoCAD 2015, though I don't think any of this has changed for some time. The big thing to keep in mind is that you are updating the BlockTableRecord (i.e. the block's definition in the drawing) and then refresh it's BlockReferences (i.e. the glorified pointers in the drawing to its definition). – bjhuffine Sep 02 '15 at 11:24
  • - Thx ! I've just two questions. Why should I call *attsync* on the block to apply the modifications ? : For example, I changed an attribute to constant. When I double-click on the block I see and I can modify the attribute. When I apply attsync on the block, it's ok I don't see (and can't modify) this attribute - And what does this line ? BlockTableRecord modelSpace = (BlockTableRecord)transaction.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead); Regards – Florian Sep 03 '15 at 13:29
  • 1
    @Florian: You have to call attsync in order to refresh the BlockReference. The ModelSpace is a BlockTableRecord in the dwg DB and so is your Block definition for "My Block". But inside the ModelSpace are BlockReferences which can effectively be viewed as intelligent pointers to the BlockTableRecord defining your block. This is why when looking at a BlockReference, you can only modify/access AttributeReferences and not AttributeDefinitions which are in the BlockTableRecord. If the BlockTableRecord is updated, the BlockReferences have to be updated too, which is typically done with attsync. – bjhuffine Sep 03 '15 at 15:23
  • 1
    @Florian: The code line: blockReference.RecordGraphicsModified(true); is the one that is effectively doing the attsync for you. It's iterating through all the BlockReferences (i.e. the pointer object) and updating them to reflect your changes to the BlockTableRecord (i.e. the object definition). Sorry about the modelSpace code there just above the iteration. I was fixing to access the model space and update its BlockReferences, but then realized I didn't have to. That was my mistake and has been removed from the example. Hopefully that all makes since. – bjhuffine Sep 03 '15 at 15:26
  • Hmmm... it's strange the the method *blockReference.RecordGraphicsModified(true);* (with the good blockReference) is well called but I should always call attsync to update the attribute as constant (and not see it in the Enhanced Attribute Editor window) – Florian Sep 03 '15 at 16:18
1

You need to change the AttributeDefinition in the block table record (property Constant), not on the AttributeReference. This property is shared with all the AttributeReference.

From the docs:

AutoCAD itself never creates a constant AttributeReference object. AutoCAD creates the AttributeReference objects for each BlockReference based on the AttributeDefinition objects within the referenced BlockTableRecord. If a constant AttributeDefinition is encountered, then AutoCAD uses the AttributeDefinition itself instead of creating a matching AttributeReference.

Maxence
  • 12,868
  • 5
  • 57
  • 69