Author Topic: Updated Block attribute Justification  (Read 256 times)

0 Members and 1 Guest are viewing this topic.

djee

  • Newt
  • Posts: 41
Updated Block attribute Justification
« on: December 13, 2016, 06:08:49 pm »
I've written a small utility that update an existing block attributes values in a side database. Everything is fine but the block attribute justification is all messed up in the process. My problem is that the attribute justification is set as "Center" but the attribute is not visually "Center". I have to manually re-set the justification by selecting "Center" again, from the attribute property drop-down. I did try the AdjustAlignment from here, but it's obviously not working for me... http://through-the-interface.typepad.com/through_the_interface/2007/07/updating-a-sp-1.html
Code: [Select]
    ar.UpgradeOpen()
    ar.TextString = attbValue
    'realign attributes after editing their values
     ar.AdjustAlignment(targetDb)
     ar.DowngradeOpen()
Anybody had a similar experience? Any way (or suggestions) to fix this?
« Last Edit: December 13, 2016, 06:12:32 pm by djee »

gile

  • Water Moccasin
  • Posts: 1999
  • Marseille, France
Re: Updated Block attribute Justification
« Reply #1 on: December 14, 2016, 02:13:22 am »
Hi,

If you only edit the AttributeReference.TextString property value, there's no reason the justification changes.

Code - C#: [Select]
  1.            using (var db = new Database(false, true))
  2.            {
  3.                db.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, null);
  4.                using (var tr = db.TransactionManager.StartTransaction())
  5.                {
  6.                    var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
  7.                    if (!bt.Has(blockName))
  8.                        return;
  9.                    var btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForRead);
  10.                    foreach (ObjectId brId in btr.GetBlockReferenceIds(true, false))
  11.                    {
  12.                        var br = (BlockReference)tr.GetObject(brId, OpenMode.ForRead);
  13.                        foreach (ObjectId attId in br.AttributeCollection)
  14.                        {
  15.                            var ar = (AttributeReference)tr.GetObject(attId, OpenMode.ForRead);
  16.                            if (ar.Tag == tag)
  17.                            {
  18.                                ar.UpgradeOpen();
  19.                                ar.TextString = attValue;
  20.                                break;
  21.                            }
  22.                        }
  23.                    }
  24.                    tr.Commit();
  25.                }
  26.                db.SaveAs(fileName, DwgVersion.Current);
  27.            }
Speaking English as a French Frog

djee

  • Newt
  • Posts: 41
Re: Updated Block attribute Justification
« Reply #2 on: December 14, 2016, 09:36:40 am »
Here's my code for block attributes modification on side database. In Vb but close to what you've shown...
Code: [Select]
Public Shared Sub UpdateAttributesInSideDatabase(ByVal FilePath As String, blockName As String, attbName As String, attbValue As String)
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim currentDb As Database = doc.Database
            Dim ed As Editor = doc.Editor
            Using targetDb As New Database(False, True)
                Try
                    targetDb.ReadDwgFile(FilePath, System.IO.FileShare.ReadWrite, True, "")
                    Using tr As Transaction = targetDb.TransactionManager.StartTransaction()
                        '' Lock the new document
                        Using acLckDoc As DocumentLock = doc.LockDocument()
                            Dim layoutDict As DBDictionary = tr.GetObject(targetDb.LayoutDictionaryId, OpenMode.ForRead)
                            For Each dicEnt As DBDictionaryEntry In layoutDict
                                Dim lay As Layout = CType(dicEnt.Value.GetObject(OpenMode.ForRead), Layout)
                                Dim layname As String = lay.LayoutName
                                ''do your stuffs in every layout
                                If layname <> "Model" Then
                                    Dim btr As BlockTableRecord = tr.GetObject(lay.BlockTableRecordId, OpenMode.ForRead)
                                    For Each id As ObjectId In btr

                                        Dim ent As Entity = TryCast(tr.GetObject(id, OpenMode.ForRead), Entity)
                                        If ent IsNot Nothing Then
                                            Dim br As BlockReference = TryCast(ent, BlockReference)
                                            If br IsNot Nothing Then
                                                Dim bd As BlockTableRecord = DirectCast(tr.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)

                                                ' ... to see whether it's a block with
                                                ' the name we're after

                                                If bd.Name.ToUpper() = blockName.ToUpper() Then
                                                    For Each arId As ObjectId In br.AttributeCollection
                                                        Dim obj As DBObject = tr.GetObject(arId, OpenMode.ForRead)
                                                        Dim ar As AttributeReference = TryCast(obj, AttributeReference)
                                                        If ar IsNot Nothing Then
                                                            ' ... to see whether it has
                                                            ' the tag we're after

                                                            If ar.Tag.ToUpper() = attbName.ToUpper() Then
                                                                ' If so, update the value
                                                                ' and increment the counter

                                                                ar.UpgradeOpen()
                                                                ar.TextString = attbValue
                                                                'realign attributes after editing their values
                                                                ar.AdjustAlignment(targetDb)
                                                                ar.DowngradeOpen()

                                                            End If
                                                        End If
                                                    Next
                                                End If
                                            End If
                                        End If
                                    Next
                                End If
                            Next
                        End Using
                        'end of code from template insert
                        tr.Commit()
                    End Using

                    HostApplicationServices.WorkingDatabase = targetDb
                    targetDb.SaveAs(FilePath, DwgVersion.Current)
                Catch ex As Autodesk.AutoCAD.Runtime.Exception
                    ed.WriteMessage(vbLf & "Error while running > " + ex.Message)
                Finally
                    HostApplicationServices.WorkingDatabase = currentDb
                End Try
            End Using
        End Sub

I've posted some picture to shown what I mean... The first picture show the updated attributes kind of left aligned, even if justification is set to "Center". The second pics show what happen after i've re-selected "Center" & applied the changes...
« Last Edit: December 14, 2016, 09:47:36 am by djee »

gile

  • Water Moccasin
  • Posts: 1999
  • Marseille, France
Re: Updated Block attribute Justification
« Reply #3 on: December 14, 2016, 10:29:38 am »
I don't see anything wrong in your code (only some unusefull statements).
Perhaps the problem is related to the attribute definitions properties (justification, lock position, ...).
Speaking English as a French Frog

djee

  • Newt
  • Posts: 41
Re: Updated Block attribute Justification
« Reply #4 on: December 14, 2016, 10:41:00 am »
Ok... Thanks a bunch gile! I'll keep digging... :woow:

djee

  • Newt
  • Posts: 41
Re: Updated Block attribute Justification
« Reply #5 on: December 14, 2016, 11:53:25 am »
Mmmm... When I run an attribute sync to my block everything goes back to normal...

Jeff H

  • Needs a day job
  • Posts: 5673
Re: Updated Block attribute Justification
« Reply #6 on: December 14, 2016, 12:38:45 pm »
I've written a small utility that update an existing block attributes values in a side database. Everything is fine but the block attribute justification is all messed up in the process. My problem is that the attribute justification is set as "Center" but the attribute is not visually "Center". I have to manually re-set the justification by selecting "Center" again, from the attribute property drop-down. I did try the AdjustAlignment from here, but it's obviously not working for me... http://through-the-interface.typepad.com/through_the_interface/2007/07/updating-a-sp-1.html
Code: [Select]
    ar.UpgradeOpen()
    ar.TextString = attbValue
    'realign attributes after editing their values
     ar.AdjustAlignment(targetDb)
     ar.DowngradeOpen()
Anybody had a similar experience? Any way (or suggestions) to fix this?
If you look at code from mentioned link http://through-the-interface.typepad.com/through_the_interface/2007/07/updating-a-sp-1.html
Code - C#: [Select]
  1.  ar.TextString = attbValue;
  2.  // Begin alignment code
  3.  Database wdb = HostApplicationServices.WorkingDatabase;
  4.  HostApplicationServices.WorkingDatabase = db;
  5.  ar.AdjustAlignment(db);
  6.  HostApplicationServices.WorkingDatabase = wdb;
  7.  // End alignment code
  8.  ar.DowngradeOpen();
  9.  
Kean is changing the working database before he calls AdjustAlignment
So to mimic his example you would
Code: [Select]
    ar.UpgradeOpen()
    ar.TextString = attbValue
    'realign attributes after editing their values
     HostApplicationServices.WorkingDatabase = targetDb
     ar.AdjustAlignment(targetDb)
     ar.DowngradeOpen()


djee

  • Newt
  • Posts: 41
Re: Updated Block attribute Justification
« Reply #7 on: December 14, 2016, 01:50:03 pm »
Bingo!! You found it... I've updated as you've suggested and all is good now. Thanks again!

Keith Brown

  • Swamp Rat
  • Posts: 550
Re: Updated Block attribute Justification
« Reply #8 on: December 14, 2016, 02:31:20 pm »
I use this when working with side databases.


Code - C#: [Select]
  1. using System;
  2. using Autodesk.AutoCAD.DatabaseServices;  
  3.  
  4. /// <summary>
  5. ///     Switches the current <c>HostApplicationServices.WorkingDatabase</c>
  6. ///     to the supplied database.
  7. /// </summary>
  8. public sealed class WorkingDatabaseSwitcher : IDisposable
  9. {
  10.   private readonly Database _previousDatabase;
  11.  
  12.   public WorkingDatabaseSwitcher(Database database)
  13.   {
  14.      this._previousDatabase = HostApplicationServices.WorkingDatabase;
  15.      HostApplicationServices.WorkingDatabase = database;
  16.   }
  17.  
  18.   public void Dispose()
  19.   {
  20.      HostApplicationServices.WorkingDatabase = this._previousDatabase;
  21.   }
  22. }
  23.  

It will automatically switch back the working database when it leaves the using statement.
« Last Edit: December 15, 2016, 08:25:54 am by Keith Brown »
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

gile

  • Water Moccasin
  • Posts: 1999
  • Marseille, France
Re: Updated Block attribute Justification
« Reply #9 on: December 15, 2016, 06:01:00 am »
IMHO, there's no need in this case to switch the working database nor to call AdjustAlignment.

Based on djee's code, this works for me :

Code - vb.net: [Select]
  1.        Public Shared Sub UpdateAttributesInSideDatabase(ByVal FilePath As String, blockName As String, attbName As String, attbValue As String)
  2.            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
  3.            Dim currentDb As Database = doc.Database
  4.            Dim ed As Editor = doc.Editor
  5.  
  6.            Using targetDb As New Database(False, True)
  7.                Try
  8.                    targetDb.ReadDwgFile(FilePath, System.IO.FileShare.ReadWrite, True, "")
  9.                    Using tr As Transaction = targetDb.TransactionManager.StartTransaction()
  10.                        Dim layoutDict As DBDictionary = tr.GetObject(targetDb.LayoutDictionaryId, OpenMode.ForRead)
  11.                        For Each dicEnt As DBDictionaryEntry In layoutDict
  12.                            Dim lay As Layout = DirectCast(dicEnt.Value.GetObject(OpenMode.ForRead), Layout)
  13.                            ''do your stuffs in every layout
  14.                            If lay.LayoutName <> "Model" Then
  15.                                Dim btr As BlockTableRecord = tr.GetObject(lay.BlockTableRecordId, OpenMode.ForRead)
  16.                                For Each id As ObjectId In btr
  17.                                    If id.ObjectClass.DxfName = "INSERT" Then
  18.                                        Dim br As BlockReference = DirectCast(tr.GetObject(id, OpenMode.ForRead), BlockReference)
  19.                                        ' ... to see whether it's a block with
  20.                                        ' the name we're after
  21.  
  22.                                        If br.Name.ToUpper() = blockName.ToUpper() Then
  23.                                            For Each arId As ObjectId In br.AttributeCollection
  24.                                                Dim ar As AttributeReference = DirectCast(tr.GetObject(arId, OpenMode.ForRead), AttributeReference)
  25.                                                ' ... to see whether it has
  26.                                                ' the tag we're after
  27.  
  28.                                                If ar.Tag.ToUpper() = attbName.ToUpper() Then
  29.                                                    ' If so, update the value
  30.                                                    ' and increment the counter
  31.  
  32.                                                    ar.UpgradeOpen()
  33.                                                    ar.TextString = attbValue
  34.                                                    'realign attributes after editing their values
  35.                                                    'ar.AdjustAlignment(targetDb)
  36.                                                    'ar.DowngradeOpen()
  37.  
  38.                                                End If
  39.                                            Next
  40.                                        End If
  41.                                    End If
  42.                                Next
  43.                            End If
  44.                        Next
  45.                        'end of code from template insert
  46.                        tr.Commit()
  47.                    End Using
  48.  
  49.                    targetDb.SaveAs(FilePath, DwgVersion.Current)
  50.                Catch ex As Autodesk.AutoCAD.Runtime.Exception
  51.                    ed.WriteMessage(vbLf & "Error while running > " + ex.Message)
  52.                End Try
  53.            End Using
  54.        End Sub
Speaking English as a French Frog