SuperNim143 发表于 2022-7-6 19:25:01

.中的NET Update块属性

我正在开发一个应用程序,使用用户输入和access数据库从模板自动生成一组图形。
 
作为其中的一部分,我有一些代码被调用来更新单个块属性。它适用于模型空间中的块!
 
我的问题是纸张空间。它没有更新现有属性,而是添加了一个同名的新属性。
 
如何访问Paperspace块属性?!?用于此操作的代码如下所示。
 
Private Sub UpdateBlockAttribute(acBlkRef As BlockReference, attTag As String, textValue As String, Optional modelSpace As Boolean = True)
       Dim acBlkTable As BlockTable
       Dim acBlkDef As BlockTableRecord
       Dim acCurLyr As ObjectId
       Dim acAttRef As DatabaseServices.AttributeReference = Nothing
       Dim attFound As Boolean = False

       Try

         acBlkTable = acTrans.GetObject(acdb.BlockTableId, OpenMode.ForRead)
         acBlkDef = DirectCast(acBlkTable(acBlkRef.Name).GetObject(OpenMode.ForRead), BlockTableRecord)

         Dim acLyrTbl As LayerTable = acTrans.GetObject(acdb.LayerTableId, OpenMode.ForRead)
         acCurLyr = acdb.Clayer
         If acLyrTbl.Has("0") Then
               acdb.Clayer = acLyrTbl("0")
         End If

         For Each acEntId In acBlkDef

               Dim acEnt As Entity = acTrans.GetObject(acEntId, OpenMode.ForRead)
               If Not IsNothing(acEnt) Then

                   If acEnt.GetType.ToString = "Autodesk.AutoCAD.DatabaseServices.AttributeDefinition" Then

                     Dim acAttDef As AttributeDefinition = DirectCast(acEnt, AttributeDefinition)

                     If Not IsNothing(acAttDef) And Not acAttDef.Constant Then

                           acAttRef = New AttributeReference
                           acAttRef.SetAttributeFromBlock(acAttDef, DirectCast(acTrans.GetObject(acBlkRef.ObjectId, OpenMode.ForRead), BlockReference).BlockTransform)

                           If acAttDef.Tag.ToString = attTag Or acAttRef.Tag.ToString = attTag Then
                               attFound = True
                               Exit For
                           End If

                     End If

                   End If

               End If

         Next

         DirectCast(acTrans.GetObject(acBlkRef.ObjectId, OpenMode.ForRead), BlockReference).AttributeCollection.AppendAttribute(acAttRef)

         'IF THE ATTRIBUTE DOES NOT EXIST, ADD A NEW ONE...
         If Not attFound Then
               acAttRef.Tag = attTag
               acAttRef.Justify = AttachmentPoint.MiddleCenter
               acTrans.AddNewlyCreatedDBObject(acAttRef, True)
               acAttRef.UpgradeOpen()
         End If

         acAttRef.TextString = textValue

         acAttRef.DowngradeOpen()


         acdb.Clayer = acCurLyr
       Catch ex As Exception
         MsgBox("Update Block Attribute: " & ex.Message)

       End Try
   End Sub

BlackBox 发表于 2022-7-6 19:31:15

 
欢迎来到CADTutor。
 
您还没有发布完整的代码或示例图,因此我(或其他人)很难准确指出您面临的问题。
 
也就是说,这可能会有所帮助:
 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;

using acApp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace BlackBox.AutoCAD.Samples
{
   class FOO
   {
       private DocumentCollection acDocs = acApp.DocumentManager;
       void UpdateBlockAttributes(string blockName, string tagString, string textString)
       {
         Document doc = acDocs.MdiActiveDocument;
         Database db = doc.Database;
         Editor ed = doc.Editor;
         tagString = tagString.ToUpper();

         // set clayer to "0" layer
         acApp.SetSystemVariable("clayer", "0");
         
         using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
         {
               // get the blocktable
               BlockTable bt =
                   (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

               // instead of iterating the entire blocktable, check to see if
               // the target block exists within this database's blocktable
               if (!bt.Has(blockName))
               {
                   // if not, then notify user, and exit
                   // uncomment the notification, if you feel it useful - I tend
                   // to not call writemessage() within non-commandmethod methods
                   //ed.WriteMessage("\nerror; Block \"{0}\" does not exist ", blockName);
                   return;
               }

               // otherwise, open the blocktablerecord
               BlockTableRecord btr =
                   (BlockTableRecord)tr.GetObject(bt, OpenMode.ForRead);
               
               // and instead, simply iterate all inserts of the target blocktablerecord
               foreach (ObjectId id in btr.GetBlockReferenceIds(true, false))
               {
                   BlockReference br =
                     (BlockReference)tr.GetObject(id, OpenMode.ForRead);

                   // <-- check for locked layer here?

                   // check for attributes
                   foreach (ObjectId attId in br.AttributeCollection)
                   {
                     AttributeReference ar =
                           tr.GetObject(attId, OpenMode.ForRead) as AttributeReference;

                     if (ar != null && ar.Tag.ToUpper() == tagString)
                     {
                           ar.UpgradeOpen();
                           ar.TextString = textString;
                           ar.DowngradeOpen();
                     }
                   }
               }

               tr.Commit();
         }
       }
   }
}

 
然后我调用sub来更新属性。(描述(CONT)是属性。)
acBlkRef = InsertBlockReference("TBClean", False, New Point3d(-0.5, 0.5, 0), True, "TITLE", Colors.Color.FromColorIndex(Colors.ColorMethod.ByAci, 0)) 'black
 
下面是函数和子函数的代码
UpdateBlockAttribute(acBlkRef, "DESCRIPTION(CONT)", strDesc)
 
Private Function InsertBlockReference(blockName As String, modelSpace As Boolean, insPt As Point3d, updateExisting As Boolean, Optional layerName As String = "", Optional layerColor As Colors.Color = Nothing) As BlockReference
       Dim acBlkTable As BlockTable
       Dim acLyrTbl As LayerTable
       Dim acCurLyrID As ObjectId
       Dim acBlkRef As BlockReference = Nothing
       Dim acSpaceID As ObjectId
       Dim acBlkTableRecord As BlockTableRecord
       Dim acBlkTableRecordID As ObjectId
       Dim acNewLyr As New LayerTableRecord

       Try
         acBlkTable = acTrans.GetObject(acdb.BlockTableId, OpenMode.ForRead)

         If IsNothing(acBlkTable) Then
               'InsertBlockReference = Nothing
               Return Nothing
         End If

         'store current layer to make it current again after function
         acLyrTbl = acTrans.GetObject(acdb.LayerTableId, OpenMode.ForRead)
         acCurLyrID = acdb.Clayer

         'if a layer is specified, set it to the current layer
         If layerName <> "" Then
               If acLyrTbl.Has(layerName) Then
                   acdb.Clayer = acLyrTbl(layerName)
               Else
                   acNewLyr.Name = layerName
                   acNewLyr.Color = layerColor
                   acLyrTbl.UpgradeOpen()
                   acLyrTbl.Add(acNewLyr)
                   acLyrTbl.DowngradeOpen()
                   acTrans.AddNewlyCreatedDBObject(acNewLyr, True)
                   acdb.Clayer = acLyrTbl(layerName)
               End If
         End If

         'check to see if the block is already in the CAD file
         If acBlkTable.Has(blockName) And updateExisting Then
               'get the BlockReference for the block
               acBlkTableRecord = DirectCast(acTrans.GetObject(acBlkTable.Item(blockName), OpenMode.ForRead), BlockTableRecord)

               Dim acObjIdColl As ObjectIdCollection = acBlkTableRecord.GetBlockReferenceIds(True, True)
               Dim acEntId As ObjectId

               For Each acEntId In acObjIdColl
                   'acBlkRef = acEntId.GetObject(OpenMode.ForRead)
                   acBlkRef = TryCast(acEntId.GetObject(OpenMode.ForWrite), BlockReference)

               Next
         Else
               'if the block is NOT in the CAD file, insert it from the dwg file
               If IO.File.Exists(Me.txtCADBlocksPath.Text & "\" & blockName & ".dwg") Then
                   Dim acBlkSourceDb As Database
                   acBlkSourceDb = New Database(False, True)
                   acBlkSourceDb.ReadDwgFile(Me.txtCADBlocksPath.Text & "\" & blockName & ".dwg", FileOpenMode.OpenForReadAndAllShare, True, Nothing)
                   acBlkTableRecordID = acdb.Insert(blockName, acBlkSourceDb, True)

                   'insert the new block
                   acBlkRef = New BlockReference(insPt, acBlkTableRecordID)

                   'select the correct block table record to insert the new block into... ModelSpace or PaperSpace
                   If modelSpace = True Then
                     acSpaceID = acBlkTable(BlockTableRecord.ModelSpace)
                   Else
                     acSpaceID = acBlkTable(BlockTableRecord.PaperSpace)
                   End If

                   acBlkTableRecord = DirectCast(acTrans.GetObject(acSpaceID, OpenMode.ForWrite), BlockTableRecord)
                   acBlkTableRecord.AppendEntity(acBlkRef)

                   acTrans.AddNewlyCreatedDBObject(acBlkRef, True)

               Else
                   MsgBox("InsertBlock: Block """ & blockName & """ DWG not found")
                   Return Nothing

               End If
         End If

       Catch ex As Exception
         MsgBox("InsertBlock: " & ex.Message)
       Finally
         acdb.Clayer = acCurLyrID

       End Try

       Return acBlkRef

   End Function
 
我希望这一切都有意义。
 
我必须在图纸上清除一些机密数据后才能发布,但如果你仍然需要的话,我可以这样做。

BIGAL 发表于 2022-7-6 19:37:15

感谢您的澄清。
 
所以请原谅我的提问,因为我忽略了一定有原因,但是如果您以编程方式插入BlockReference,然后修改所述BlockReference的属性,为什么不手动保存更正的块的副本并插入/覆盖BlockTableRecord呢?
 
您甚至可以首先迭代我上面介绍的现有插入,根据需要存储值和属性,然后根据需要在结果块中填充所述值。
 
干杯

BlackBox 发表于 2022-7-6 19:40:47

考虑:
 
Private Sub UpdateBlockAttribute(acBlkRef As BlockReference, attTag As String, textValue As String, Optional modelSpace As Boolean = True)
       Dim acBlkTable As BlockTable
       Dim acBlkDef As BlockTableRecord
       Dim acCurLyr As ObjectId
       Dim acAttRef As DatabaseServices.AttributeReference = Nothing
       Dim attFound As Boolean = False

       Try

         acBlkTable = acTrans.GetObject(acdb.BlockTableId, OpenMode.ForRead)
         'acBlkDef = DirectCast(acBlkTable(acBlkRef.Name).GetObject(OpenMode.ForRead), BlockTableRecord)

         Dim acLyrTbl As LayerTable = acTrans.GetObject(acdb.LayerTableId, OpenMode.ForRead)
         acCurLyr = acdb.Clayer
         If acLyrTbl.Has("0") Then
               acdb.Clayer = acLyrTbl("0")
         End If

         If acBlkTable.Has(acBlkRef.Name) Then
               acBlkDef = acTrans.GetObject(acBlkRef.Id, OpenMode.ForRead)


         End If
         For Each acEntId In acBlkDef

               Dim acEnt As Entity = acTrans.GetObject(acEntId, OpenMode.ForRead)
               If Not IsNothing(acEnt) Then

                   If acEnt.GetType.ToString = "Autodesk.AutoCAD.DatabaseServices.AttributeDefinition" Then

                     Dim acAttDef As AttributeDefinition = DirectCast(acEnt, AttributeDefinition)

                     If Not IsNothing(acAttDef) And Not acAttDef.Constant Then

                           acAttRef = New AttributeReference
                           acAttRef.SetAttributeFromBlock(acAttDef, DirectCast(acTrans.GetObject(acBlkRef.ObjectId, OpenMode.ForRead), BlockReference).BlockTransform)

                           If acAttDef.Tag.ToString = attTag Or acAttRef.Tag.ToString = attTag Then
                               attFound = True
                               Exit For
                           End If

                     End If

                   End If

               End If

         Next

         DirectCast(acTrans.GetObject(acBlkRef.ObjectId, OpenMode.ForRead), BlockReference).AttributeCollection.AppendAttribute(acAttRef)

         'IF THE ATTRIBUTE DOES NOT EXIST, ADD A NEW ONE...
         If Not attFound Then
               acAttRef.Tag = attTag
               acAttRef.Justify = AttachmentPoint.MiddleCenter
               acTrans.AddNewlyCreatedDBObject(acAttRef, True)
               acAttRef.UpgradeOpen()
         End If

         acAttRef.TextString = textValue

         acAttRef.DowngradeOpen()

         acBlkDef.SynchronizeAttributes()

         acdb.Clayer = acCurLyr
       Catch ex As Exception
         MsgBox("Update Block Attribute: " & ex.Message)

       End Try
   End Sub

SuperNim143 发表于 2022-7-6 19:43:51

对不起,我没有回应。我有一段时间不在办公室了。
 
这个程序将被我们的起草者使用。这个想法是,它将是相当动态的。他们将能够将其块(使用适当的块名和属性名)放置在文件夹中,并将程序指向该位置。这将使他们能够使砌块外观与客户相符。程序将根据他们的选择为他们更新该块。查找块中存在的属性并在不存在时添加,将确保块中存在所有必需字段。
 
我们正试图引导起草领导朝着更稳健的方向发展,但目前这正是他们想要的。
 
您发送的最后一段代码能否解决纸张空间属性问题?
 
据我所知,我的问题不是打开或读取paperspace块,而是定位属性。
由于某种原因,当它比较时。tag to attTag它永远不会找到匹配项,即使它确实存在。
这只是在纸上。这就是我不明白的。
问题是否可能是我没有将其指向特定布局?
 
现在我回到办公室,我将仔细查看您提供的代码。
 
再次感谢您的投入。

BlackBox 发表于 2022-7-6 19:51:53

 
别担心;最近我自己工作了太多的时间,而且似乎不会很快停止。
 
在任何情况下,发布一个示例图形可能是明智的,您可以用这种方式复制这个问题,这样我们就不必从头开始设置示例数据集和代码等,以便尝试和帮助?
 
干杯

BlackBox 发表于 2022-7-6 19:55:31

terminal\u template\u已擦除。图纸
 
附着了模板dwg的擦除版本。在这种情况下,我正在更新paperspace中TBCLEAN标题栏上的DESCRIPTION(CONT)属性。
 
就像我说的,它找不到现有的属性,所以它会创建一个同名的新属性并更新该值。
 
经过进一步研究,我想知道这个问题是否源于没有选择布局选项卡。我开始尝试把它融入到组合中,但我还没有成功。请参阅下面我更新的子代码。但我觉得我错过了一步。
 
我得到一个响应,它没有设置为对象的实例。(适用于所有属性)
 

var btr = <BlockTable>["<BlockName>"].GetObject(<OpenMode>);

SuperNim143 发表于 2022-7-6 19:59:22

感谢您如此快速地发布图纸,并提供更多信息。
 
我会尽快找到答案的——我现在正在完成其他人的项目(为什么你要等到提交文件结束,做垂直剖面,卫生运行,修改风暴(如果有的话),并设计供水和供水干管的垂直方向,我无能为力,但这就是我被要求做的,dah dah dahhh.Grrr)。
 
 
 
此外,您计划支持什么版本?
 
干杯

BlackBox 发表于 2022-7-6 20:04:49

AutoCad 2013和。net framework 4

SuperNim143 发表于 2022-7-6 20:08:58

我觉得我离得很近,但仍然缺少一些东西。
我已经对因子布局进行了修改。
我已经能够确认它现在正在迭代正确的块,并且确实拉入了该属性,但是,它仍然无法识别标记是否等于传入的attTag。我附上了我的输出问题的快速屏幕截图。如果查看属性名称,可以看到它创建了一个具有相同名称的新属性。
 
Private Sub UpdateBlockAttribute(acBlkRef As BlockReference, attTag As String, textValue As String, Optional modelSpace As Boolean = True)
       Dim acBlkTable As BlockTable = Nothing
       Dim acBlkDef As BlockTableRecord
       Dim acCurLyr As ObjectId
       Dim acAttRef As DatabaseServices.AttributeReference = Nothing
       Dim attFound As Boolean = False
       Dim acSpaceID As ObjectId

       Try
         acBlkTable = acTrans.GetObject(acdb.BlockTableId, OpenMode.ForRead)

         If modelSpace = False Then
               acSpaceID = acBlkTable(BlockTableRecord.PaperSpace)
         Else
               acSpaceID = acBlkTable(BlockTableRecord.ModelSpace)
         End If

         acBlkDef = DirectCast(acTrans.GetObject(acSpaceID, OpenMode.ForRead), BlockTableRecord)


         'acBlkDef = DirectCast(acBlkTable(acBlkRef.Name).GetObject(OpenMode.ForRead), BlockTableRecord)

         Dim acLyrTbl As LayerTable = acTrans.GetObject(acdb.LayerTableId, OpenMode.ForRead)
         acCurLyr = acdb.Clayer
         If acLyrTbl.Has("0") Then
               acdb.Clayer = acLyrTbl("0")
         End If

         For Each acEntId In acBlkDef

               Dim acEnt As Entity = acTrans.GetObject(acEntId, OpenMode.ForRead)
               If Not IsNothing(acEnt) Then

                   If acEnt.GetType.ToString = "Autodesk.AutoCAD.DatabaseServices.AttributeDefinition" Then

                     Dim acAttDef As AttributeDefinition = DirectCast(acEnt, AttributeDefinition)

                     If Not IsNothing(acAttDef) And Not acAttDef.Constant Then

                           acAttRef = New AttributeReference
                           acAttRef.SetAttributeFromBlock(acAttDef, DirectCast(acTrans.GetObject(acBlkRef.ObjectId, OpenMode.ForRead), BlockReference).BlockTransform)

                           If acAttDef.Tag.ToString = attTag Or acAttRef.Tag.ToString = attTag Then
                               attFound = True
                               Exit For
                           End If

                     End If

                   End If

               End If

         Next

         DirectCast(acTrans.GetObject(acBlkRef.ObjectId, OpenMode.ForRead), BlockReference).AttributeCollection.AppendAttribute(acAttRef)

         'IF THE ATTRIBUTE DOES NOT EXIST, ADD A NEW ONE...
         If Not attFound Then
               acAttRef.Tag = attTag
               acAttRef.Justify = AttachmentPoint.MiddleCenter
               acTrans.AddNewlyCreatedDBObject(acAttRef, True)
               acAttRef.UpgradeOpen()
         End If

         acAttRef.TextString = textValue

         acAttRef.DowngradeOpen()

         acBlkDef.SynchronizeAttributes()
         acdb.Clayer = acCurLyr
       Catch ex As Exception
         MsgBox("Update Block Attribute: " & ex.Message & acAttRef.BlockName.ToString & " - " & acAttRef.Tag.ToString)

       End Try
   End Sub
 
纸张空间块。docx文件
页: [1] 2
查看完整版本: .中的NET Update块属性