.IsDynamicBlock 返回 false ?
大家好,在工作中被困了几个小时,不知道你们谁能帮助我?
(我打赌你能)
我正在做的事情:
-有一个包含相关块和动态块的“主dwg ”
-运行一个例程,用块参考填充新生产图的模型空间,如果块还没有出现在新生产图中,则从“主DWG”导入。
-导入“常规”和动态块。
-能够在需要的地方和时间设置属性和动态特性
-在该初始插入方法之后,所有的块都被插入并在适当的位置标注尺寸,需要进行一定的检查。
我遍历模型空间并基于BlockRef。Name需要执行某个动作
-这适用于我的常规块,但是动态块都有那些匿名的名字,比如“*U24”,使它们避开我的名字检查。
找到了获取动态块的“EffectiveName”的解决方案:
Public Shared Function EffectiveName(ByVal blkref As BlockReference) As String
If blkref.IsDynamicBlock Then
Return DirectCast(blkref.DynamicBlockTableRecord.GetObject(OpenMode.ForRead), BlockTableRecord).Name
Else
Return blkref.Name
End If
End Function
但问题是:blkref。IsDynamicBlock allways返回false!
因此,即使我在模型空间中的动态块插入良好,属性和动态特性设置正确,并且在编程上运行良好,它们也不会被识别为动态块?
为什么会这样?
**** Hidden Message ***** 看不到更多的代码。IsDynamicBlock被调用,我几乎可以肯定这个调用是以这样的方式进行的:您在一个事务中获得一个Blockreference对象,然后在获得BlockReference的那个事务之外传递BlockReference对象(以获得它的“有效名称”)。这就是IsDynamicBlock返回false的原因,即使您确实知道该块是动态块引用。
传递通过事务获得的对象是不好的,并且正如您刚刚经历的那样,在事务范围之外获得DBObject的属性可能不会得到您想要的东西。相反,您总是在事务之间传递ObjectID,并在活动事务的范围内获取DBObject的属性。 嘿n.yuan,谢谢回复!
这就是我这样做的方式(代码方面):
步骤1)插入我的动态块:
...
' assure the desired doorsketchBlock is present in the blocktable
acadBlockId = Acad.searchOrImportBlock(Acad.SketchblocksFileName, blockName)
' insert the block in modelspace
acadblockref = Acad.InsertBlock(blockName, insPnt, 1, 1, 1, _acParentBlockref.Rotation)
'Set Dynamic properties
AttVals.Clear()
AttVals.Add("Lookup|" & dimNuttigeBreedte & " x " & dimPaneelBreedte)
AttVals.Add("Paneeldikte|" & _acParentBlockref.ScaleFactors.Y)
AttVals.Add("Draairichting|" & conDraairichting)
Acad.set_DynamicBlockProperties(acadblockref, AttVals)
'Set Attributes
AttVals.Clear()
AttVals.Add("InventTransId|" & genInventTransId)
AttVals.Add("DIM|" & dimNuttigeBreedte & "|" & dimPaneelBreedte & "|" & dimNuttigeHoogte & "|" & _acParentBlockref.ScaleFactors.Z & "|" & doorPanelConn)
AttVals.Add("ONDERBOUW|" & IIf(conVerzonkenOpstelling, _
Acad.get_AttValByIdx(_acParentBlockref, 3) & "|" & conVerzonkenOpstelling, _
Acad.get_AttValByIdx(_acParentBlockref, 3)))
Acad.set_BlockAttributes(acadblockref, AttVals)
...
4种方法在上面的代码中发挥作用:
Acad.searchOrImportBlock(检查当前绘图中是否已经存在所需的块可块,如果没有,它将从“主绘图”中获取它)
Acad.InsertBlock(知道所需的块存在于当前绘图的可块中,它会将其插入模型空间并返回一个BlockResources对象)
Acad.set_DynamicBlockProperties(用于设置给定BlockResources的动态属性)
Acad.set_BlockAttributes(用于设置属性值给定的Block引用)
Acad.searchOrImportBlock
Shared Function searchOrImportBlock(_sourceFileName As String, _blockName As String) As ObjectId
' Get the current document and database
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
' Lock the document
Using acLckDoc As DocumentLock = acDoc.LockDocument()
' Start a transaction in the database
Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
' Get the Block table for the current database
Dim acBlockTbl As BlockTable = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
' If found in local BlockTableRecord
If acBlockTbl.Has(_blockName) Then
Return acBlockTbl(_blockName)
End If
End Using ' Dispose of the transaction
End Using ' Unlock the document
' If not found in local BlockTableRecord then Import from _sourceFileName
Return importBlockFromSourceFile(_sourceFileName, _blockName)
End Function
Shared Function importBlockFromSourceFile(_sourceFileName As String, _blockName As String) As ObjectId
Dim sourceDb As New Database(False, True)
Dim acObjIdColl As ObjectIdCollection = New ObjectIdCollection()
' Read the DWG into a side database
sourceDb.ReadDwgFile(_sourceFileName, System.IO.FileShare.Read, True, "")
Using acTrans As Transaction = sourceDb.TransactionManager.StartTransaction()
' Open the block table
Dim bt As BlockTable = DirectCast(acTrans.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, False), BlockTable)
If bt.Has(_blockName) Then
acObjIdColl.Add(bt(_blockName))
'SendCommandMessage(vbCrLf & "Imported block: '" & _blockName & "' from '" & _sourceFileName & "'" & vbCrLf)
End If
'' Check each block in the block table
'For Each btrId As ObjectId In bt
' Dim btr As BlockTableRecord = DirectCast(acTrans.GetObject(btrId, OpenMode.ForRead, False), BlockTableRecord)
' If btr.Name = _blockName Then
' acObjIdColl.Add(btr.ObjectId)
' SendCommandMessage(vbCrLf & "Importing block: " & btr.Name)
' End If
' btr.Dispose()
'Next
End Using
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
' Lock the document
Using acLckDoc As DocumentLock = acDoc.LockDocument()
' Start a transaction in the database
Using acTrans = acDoc.TransactionManager.StartTransaction()
' Open the Block table for read
Dim acBlkTblNewDoc As BlockTable
acBlkTblNewDoc = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
' Open the Block table record Model space for read
Dim acBlkTblRecNewDoc As BlockTableRecord
acBlkTblRecNewDoc = acTrans.GetObject(acBlkTblNewDoc(BlockTableRecord.ModelSpace), OpenMode.ForRead)
' Clone the objects to the new database
Dim acIdMap As IdMapping = New IdMapping()
acCurDb.WblockCloneObjects(acObjIdColl, acBlkTblRecNewDoc.ObjectId, acIdMap, DuplicateRecordCloning.Ignore, False)
' Commit the transaction
acTrans.Commit()
End Using ' Dispose of the transaction
End Using ' Unlock the document
'Return ObjectId
Return acObjIdColl(0)
End Function
Acad.InsertBlock
Shared Function InsertBlock(ByVal _blockName As String, ByVal insPt As Point3d, ByVal xBlkScale As Double, _
ByVal yBlkScale As Double, ByVal zBlkScale As Double, ByVal ang As Double) As BlockReference
' Get the current document and database
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
' Lock the document
Using acLckDoc As DocumentLock = acDoc.LockDocument()
' Start a transaction in the database
Using acTrans = acDoc.TransactionManager.StartTransaction()
Dim blkTable As BlockTable = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
If blkTable.Has(_blockName) Then
Dim blkObjId As ObjectId = blkTable(_blockName)
Dim blkRef As BlockReference = New BlockReference(insPt, blkObjId)
blkRef.SetDatabaseDefaults()
blkRef.ScaleFactors = New Scale3d(xBlkScale, yBlkScale, zBlkScale)
blkRef.Rotation = ang
Dim blkTblRec As BlockTableRecord
' Assumes the current space was already changed to.
blkTblRec = acTrans.GetObject(acCurDb.CurrentSpaceId, OpenMode.ForWrite)
blkTblRec.AppendEntity(blkRef)
acTrans.AddNewlyCreatedDBObject(blkRef, True)
' add the attribute definitions.
Dim blkTblR As BlockTableRecord = blkObjId.GetObject(OpenMode.ForRead)
For Each objId As ObjectId In blkTblR
Dim obj As DBObject = objId.GetObject(OpenMode.ForRead)
If TypeOf obj Is AttributeDefinition Then
Dim ad As AttributeDefinition = objId.GetObject(OpenMode.ForRead)
Dim ar As AttributeReference = New AttributeReference()
ar.SetAttributeFromBlock(ad, blkRef.BlockTransform)
ar.Position = ad.Position.TransformBy(blkRef.BlockTransform)
blkRef.AttributeCollection.AppendAttribute(ar)
acTrans.AddNewlyCreatedDBObject(ar, True)
End If
Next
' Commit the transaction
acTrans.Commit()
Return blkRef
End If
End Using ' Dispose of the transaction
End Using ' Unlock the document
End Function
Acad.set_DynamicBlockProperties
Shared Sub set_DynamicBlockProperties(_blkRef As BlockReference, _attVals As List(Of String))
' Get the current document and database, and start a transaction
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
' Lock the new document
Using acLckDoc As DocumentLock = acDoc.LockDocument()
' Start a transaction in the new database
Using acTrans = acDoc.TransactionManager.StartTransaction()
'Open _blkRef For writing
_blkRef = DirectCast(acTrans.GetObject(_blkRef.Id, OpenMode.ForWrite), BlockReference)
For Each dynamicProperty As DynamicBlockReferenceProperty In _blkRef.DynamicBlockReferencePropertyCollection
Dim recievedValue As String = get_AttVal(dynamicProperty.PropertyName, _attVals)
If Not String.IsNullOrEmpty(recievedValue) Then
If is_DynamicValueAllowed(recievedValue, dynamicProperty) Then
If IsNumeric(recievedValue) Then
dynamicProperty.Value = CDbl(recievedValue)
Else
dynamicProperty.Value = recievedValue
End If
Else
MsgBox("Voor DynamicBlock '" & _blkRef.Name & "'" & _
" werd voor property '" & dynamicProperty.PropertyName & "'" & _
" getracht de niet-toegestane waarde '" & recievedValue & "' mee te geven." & _
vbLf & vbLf & _
"Gelieve dit te controleren !", vbOKOnly + MsgBoxStyle.Exclamation)
End If
End If
Next
' Commit the transaction
acTrans.Commit()
End Using ' Dispose of the transaction
End Using ' Unlock the document
End Sub
Acad.set_BlockAttributes
Shared Sub set_BlockAttributes(_blkRef As BlockReference, _attVals As List(Of String))
' Get the current document and database, and start a transaction
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
' Lock the new document
Using acLckDoc As DocumentLock = acDoc.LockDocument()
' Start a transaction in the new database
Using acTrans = acDoc.TransactionManager.StartTransaction()
Dim attCol As AttributeCollection = _blkRef.AttributeCollection
For Each attId As ObjectId In attCol
Dim attRef As AttributeReference = DirectCast(acTrans.GetObject(attId, OpenMode.ForWrite), AttributeReference)
Dim recievedValue As String = get_AttVal(attRef.Tag, _attVals)
If Not String.IsNullOrEmpty(recievedValue) Then attRef.TextString = recievedValue
Next
' Commit the transaction
acTrans.Commit()
End Using ' Dispose of the transaction
End Using ' Unlock the document
End Sub
我不认为上述代码有任何功劳。没有一个是完全编译粘贴的,最近它是完全手工编写的吗?
步骤2)遍历插入的块:
我已经收集了“Sketch”层中的所有Block引用,现在我想评估它们,并根据它们的名称采取行动
'Perform individual convertion per block in the SketchBlocksCollection, based on it's type (Name)
For Each acSketchBlockRef As BlockReference In SketchBlocksCollection
Select Case acSketchBlockRef.Name
Case "SketchHoekBlock V"
convert_Corner_vertical(acSketchBlockRef, SketchBlocksCollection)
Case "SketchVloerBlock"
Dim MaxUsedFloorPanelLenght = convert_Floor(acSketchBlockRef, SketchBlocksCollection, SketchConversionSettings, sketchOrigins, MaxUsedLength)
MaxUsedLength = Math.Max(MaxUsedLength, MaxUsedFloorPanelLenght)
Case "SketchPlafondBlock"
Dim MaxUsedCielingPanelLenght = convert_Cieling(acSketchBlockRef, SketchBlocksCollection, SketchConversionSettings, sketchOrigins, MaxUsedLength)
MaxUsedLength = Math.Max(MaxUsedLength, MaxUsedCielingPanelLenght)
Case "SketchPaneelBlock"
convert_Wall(acSketchBlockRef, SketchBlocksCollection, SketchConversionSettings, SketchHorizontalCornerBlocksCollection, SketchDeurBlocksCollection)
Case "SketchDraaiDeurBlock", "SketchDraaiDeurDubbelBlock", "SketchSchuifDeurBlock"
convert_Door(acSketchBlockRef) 'code never reached
Case "SketchVBNBlock"
convert_VBN(acSketchBlockRef, SketchConversionSettings, sketchOrigins)
Case Else
End Select
Next acSketchBlockRef
这里出错了:
Case"SketchDraaiDeurBlock
因此acSketchBlockRef.Name计算结果为(例如)"*U24",而不是"SketchDraaiDeurBlock"。
我尝试了这个:
For Each acSketchBlockRef As BlockReference In SketchBlocksCollection
Select Case EffectiveName(acSketchBlockRef)
Case "SketchHoekBlock V"
convert_Corner_vertical(acSketchBlockRef, SketchBlocksCollection)
Case "SketchVloerBlock"
Dim MaxUsedFloorPanelLenght = convert_Floor(acSketchBlockRef, SketchBlocksCollection, SketchConversionSettings, sketchOrigins, MaxUsedLength)
MaxUsedLength = Math.Max(MaxUsedLength, MaxUsedFloorPanelLenght)
Case "SketchPlafondBlock"
Dim MaxUsedCielingPanelLenght = convert_Cieling(acSketchBlockRef, SketchBlocksCollection, SketchConversionSettings, sketchOrigins, MaxUsedLength)
MaxUsedLength = Math.Max(MaxUsedLength, MaxUsedCielingPanelLenght)
Case "SketchPaneelBlock"
convert_Wall(acSketchBlockRef, SketchBlocksCollection, SketchConversionSettings, SketchHorizontalCornerBlocksCollection, SketchDeurBlocksCollection)
Case "SketchDraaiDeurBlock", "SketchDraaiDeurDubbelBlock", "SketchSchuifDeurBlock"
convert_Door(acSketchBlockRef)
Case "SketchVBNBlock"
convert_VBN(acSketchBlockRef, SketchConversionSettings, sketchOrigins)
Case Else
convert_Door(acSketchBlockRef)
End Select
Next acSketchBlockRef
使用方法'有效名称'being:
Public Shared Function EffectiveName(ByVal blkref As BlockReference) As String
If blkref.IsDynamicBlock Then
Return DirectCast(blkref.DynamicBlockTableRecord.GetObject(OpenMode.ForRead), BlockTableRecord).Name
Else
Return blkref.Name
End If
End Function
但是在这里,blkref.IsDynamicBlock总是返回false。
这是一个满嘴的!
有什么想法吗? 快速说明,在您的 importBlockFromSourceFile() 函数中,您应该在 using 变量中创建端数据库,这样您就不必担心它的处置(您没有这样做)
关于您遇到的问题,您能告诉我您正在做什么来创建您正在迭代的 SketchBlocksCollection 吗? 好吧,只有您在“步骤2”中显示的代码与问题相关(对于每个...下一步选择案例...在其中)。但是,您没有显示“对于每个...接下来是在.
对于每个...Next 只有在事务范围内,并且SketchBlockCollection中的块引用在事务范围内获得时才有效,如下所示:
''在某个地方,您可能有这样的代码来构建您的块引用集合
公共函数GetSketchBlocks() 作为块引用
块的列表 作为块引用列表=新....
''您可能使用了其中一个 Editor.SelectXXX() methos
Using tran As Transaction=MyDb.TransactionManager.StartTransaction()
''获取 Blockrefernce 对象并添加到 StechBlockCollection 此处
的块。Add(tran.GetObject(.....)
传输。Commit()
End Using
Return blocks
End Function
''然后你可以运行 For Each ...在此
阶段,Blockreference 对象不在获取它的事务范围之外
,因此一些属性会丢失(例如 IsDynamicBlock)
对于每个 blk 作为 SketchCollection 中的 Blockreference
Select Case EffectiveName()。ToUpper()
....
结束 选择
下
一步 对于该代码结构,您可能认为最好将用于将BlockReference收集到单独方法的集合中的代码,以便它可以在其他地方重用,例如
公共函数GetSketchBlocks()作为BlockReference列表
。
结束函数
这是出现问题时:您需要一个事务将选定的 ObjectId 转换为 BlockReference,以便将它们放入集合中。在方法结束时,事务完成,您将 DBObject(在本例中为 BlockReference)传递给其他方法以进行进一步处理。然后,正如我在前面的回复中指出的那样,您遇到了问题:您应该传递ObjectId而不是DBObject,并且仅在需要时访问当前事务中的DBObject属性。
所以,你应该有一个这样的方法:
公共函数GetSketchBlocks() As ObjectIdCollection
....
'' 只返回 ObjectId 或 ObjectId 的集合,以便其他进程重用此代码
End Function
在需要读取 BlockReference' 属性的地方,您可以'
''获取 selelcted 块作为 ObjectId 的集合,而不是 DBObject
SktechBlocks=GetSketchBlocks()
'''在事务中使用
tran As Transaction=....()
对于每个 id 作为 SketchBlockCollection
Dim BlkRef 作为 BlockReference = tran。GetObject(id,...)
选择案例有效名称(blkReg)
....
结束 选择
下一个
tran.提交()
结束使用
这太有意义了!
我不再工作了,现在回家了。我会按照你说的重新做我的代码。
你说得对,我确实通过一个返回“Block ref集合”的函数收集我的SketchBlock(Blockrefs)。
它被称为“collect_SketchBlocks”(或类似的东西,这里没有它)
它只是抓取具有“SKETCH”作为其层的Blockrefs的ModelSpace,当找到时将它们添加到集合中。
完成后,...它关闭了它正在使用的事务。
从来没有想过这会给我带来这个麻烦...
如果我理解正确,我将不得不创建集合,
遍历它并
执行所需的操作
所有这些都在1个单一的眼睛下交易?
几个星期以来,我已经对AutoCAD. NET api了如指掌,并且做了很多漂亮的事情。
然而,我仍然觉得我有很多东西要学,有时我错过了一些关键概念。
。我发现网络特定留档非常肤浅。
我会在10小时内报告我的发现!
谢谢您的指导!
如果您喜欢维护每个函数事务,那么您需要将子例程调用包装在事务中以保持对象打开或传递ObjectIds。如果绝对需要事务,我喜欢使用子例程中的顶部事务:
Function main()
...
使用Transaction tr=db.TransactionManager.StartTransaction()
Dim DbObjectCollection block=get_blocks(db)
sort_blocks(block)
...
结束使用
End Function
Functionget_Blocks(db As Database)As DbObjectCollection
Dim Transaction tr=db.TransactionManager.TopTransaction
如果tr==null然后抛出新的ArgumentNullException(“在事务范围之外调用的函数”)
...获取块
结束函数 看起来很快,很难理解,但看不到您的InsertBlock函数是如何工作的。
看起来您创建并将其添加到事务中,然后提交将关闭对象的事务,然后返回块引用,并且看不到它在嵌套事务中要将其传递给。
如果您通过Ref而不是Val传递block引用会发生什么?
我知道,因为我从未意识到这会是个问题
每次需要挖掘时,我都使用一个单独的*新*事务。(插入实体、编辑块、移动对象)
实际上,我在代码中编写的每个方法都有自己的事务
我非常理解结束一笔交易会给后续业务带来什么样的问题
将使用此方法
在我的辩护中,或者在我的代码中:一切都按照设计的方式工作
如果不是因为那次检查(.IsDynamic)一直失败,我永远也不会更聪明
所有其他功能都已实际运行(插入、属性、转换和擦除“常规”块)
我现在将讨论它,并将向您汇报
页:
[1]
2