| | | Gut zu wissen: Hilfreiche Tipps und Tricks aus der Praxis prägnant, und auf den Punkt gebracht für Autodesk Produkte |
Autor
|
Thema: Blöcke per Blocktablerecord einlesen und bearbeiten (2082 mal gelesen)
|
ManuelKuhn Mitglied Techniker und DvD :-)
Beiträge: 100 Registriert: 23.03.2005 Intel XEON W3503 @ 2.4GHz 8 GB DDR3 NVIDIA QUADRO FX3800 WinXP Prof SP3 x64 ACAD 2007 + ProSteel 17.2/ 18 ACAD 2010 + ProSteel V8i S3 Rhino 3D V4 Autodesk VIZ-2006 Max2011 Design Visual Studio 2008
|
erstellt am: 24. Mrz. 2011 08:34 <-- editieren / zitieren --> Unities abgeben:
Moin Moin zusammen, ich hänge hier irgendwie an einem Problem, wo ich nicht weiterkomme.... Folgender Sachverhalt: Ich habe vor, alle Blöcke in allen Layouts einzulesen, die Doppelten auszufiltern, dann die vorhandenen Attribute zu bearbeiten und die Änderungen in die entsprechenden Blöcke zurück zu schreiben. Bisher gehe ich so vor, dass ich mir die Blöcke in einem "Listview" anzeigen lasse, der User wählt dann den gewünschten Block aus, diesen Blocknamen übergebe ich dann an ein neues Formular, das wiederrum die Zeichnung nach dem gewählten Blocknamen durchsucht und dann die enthaltenen Attribute und ihre Werte in einem "DataGridView" darstellen soll, nun kann der User diese dort bearbeiten und anschließen die Änderungen speichern. Das einlesen der Blocknamen ins Listview klappt ohne Probleme über folgenden Code: (Der Filter für die Doppelten Definitionen fehlt noch)
Code:
Private Sub frmMainDialoge_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim acCurDb As Database = acDoc.Database Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction() Dim bt As BlockTable bt = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) For Each Acadid As ObjectId In bt Dim dbobj As Autodesk.AutoCAD.DatabaseServices.DBObject = acTrans.GetObject _ (Acadid, OpenMode.ForRead) Dim btr As BlockTableRecord = TryCast(dbobj, BlockTableRecord) If btr.IsLayout = False Then Me.lstBBlocks.Items.Add(btr.Name) End If dbobj.Dispose() Next bt.Dispose() End Using End Sub
Die Übergabe an das neue Formular, mache ich über eine Settingsvariable, da ich irgendwie keine andere Möglichkeit gefunden habe. Es gibt wohl die Möglichkeit, das ganze über ein "Overloads Sub" zu machen, das funktioniert aber nur, wenn das Projekt ein "Windows-Forms" Projekt ist und keine "Class Library"...
Code:
Private Sub btnEdit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEdit.Click If lstBBlocks.SelectedIndex = -1 Then MsgBox("Please choose Block to edit!", MsgBoxStyle.Information, "Info") Exit Sub End If My.Settings.selitem = lstBBlocks.SelectedItem Dim frmProbs As New frmPropbs frmProbs.ShowDialog() End Sub
Hier, im neuen Formular, kommt nun mein Problem; ich durchsuche ja nun die Zeichnungsdatenbank nochmals, um den entsprechenden Block mit dem gewählten Namen zu finden um anschließend seine Attribute in mein "DataGridView" zu schreiben (Momentan gebe ich mir zum Testen nur eine Messagebox mit dem Tag aus), allerdings bekomme ich das irgendwie nicht hin... hier der Code:
Code:
Private Sub frmProbs_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim acCurDb As Database = acDoc.Database Dim acTrans As Transaction = acCurDb.TransactionManager.StartTransaction() Dim bt As BlockTable Dim AcadBlkRef As BlockReference Dim AcadAttCol As AttributeCollection Dím AcadAttID As ObjectId Dim AcadAttRef As AttributeReference Dim BlockId As ObjectId Dim btr As New BlockTableRecord Try bt = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) For Each AcadId As ObjectId In bt Dim dbobj As Autodesk.AutoCAD.DatabaseServices.DBObject = acTrans.GetObject _ (AcadId, OpenMode.ForRead) btr = DirectCast(acTrans.GetObject(AcadId, OpenMode.ForRead), BlockTableRecord) If btr.Name = My.Settings.selitem Then BlockId = AcadId Exit For Else : End If Next btr.Dispose() AcadBlkRef = acTrans.GetObject(BlockId, OpenMode.ForRead) AcadAttCol = AcadBlkRef.AttributeCollection For Each AcadAttID In AcadAttCol AcadAttRef = DirectCast(acTrans.GetObject(AcadAttID, OpenMode.ForRead), _ AttributeReference) MsgBox(AcadAttRef.Tag) Next bt.Dispose() acTrans.Commit() Catch ex As Autodesk.AutoCAD.Runtime.Exception MsgBox("Exception: " + ex.Message) Finally acTrans.Dispose() End Try End Sub
Beim Punkt "AcadBlkRef = acTrans.GetObject(BlockId, OpenMode.ForRead)" fliege ich immer raus, mit dem Fehler:
Zitat: Unable to cast object of type 'Autodesk.AutoCAD.DatabaseServices.BlockTableRecord' to type 'Autodesk.AutoCAD.DatabaseServices.BlockReference'.
mir ist schon irgendwie klar, was passiert... die Variable BlockId kommt ja aus meinem "Blocktablerecord", aber sie stellt doch nur die ID dar, welche ich hier meiner BlockReferenz zuweisen will, ich werd da nicht schlau draus... Hoffe jemand hat ne Idee für mich... Grüße Manu PS: Sorry, ich weiß es ist viel zu lesen, aber ich hab mir gedacht, ich schreibe den kompletten zusammenhang, dass es verständlicher ist, wo was herkommt. ------------------ Etwaige Rechtschreibfehler sind gewollt und dienen der allgemeinen Belustigung Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Brischke Moderator CAD on demand GmbH
Beiträge: 4171 Registriert: 17.05.2001 AutoCAD 20XX, defun-tools
|
erstellt am: 24. Mrz. 2011 12:14 <-- editieren / zitieren --> Unities abgeben: Nur für ManuelKuhn
Hallo ManuelKuhn. es ist, wie die Fehlermeldung schon sagt: Du hast die Id eines BlockTableRecords (Blockdefinition) und willst diese casten zu einer Blockreferenz(Insert). Das funzt nicht. Du kannst die BlockReferenzen aus dem geöffneten BlocktableRecord mit der Methode GetReferences (oder so ähnlich) ermitteln. Dann hast du alle ID's der Blockreferenzen. Bei Fragen ... Grüße Holger ------------------ Holger Brischke CAD on demand GmbH Individuelle Lösungen von Heute auf Morgen. defun-tools Das Download-Portal für AutoCAD-Zusatzprogramme! Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
ManuelKuhn Mitglied Techniker und DvD :-)
Beiträge: 100 Registriert: 23.03.2005 Intel XEON W3503 @ 2.4GHz 8 GB DDR3 NVIDIA QUADRO FX3800 WinXP Prof SP3 x64 ACAD 2007 + ProSteel 17.2/ 18 ACAD 2010 + ProSteel V8i S3 Rhino 3D V4 Autodesk VIZ-2006 Max2011 Design Visual Studio 2008
|
erstellt am: 25. Mrz. 2011 09:06 <-- editieren / zitieren --> Unities abgeben:
Guten Morgen Holger, vielen Dank, das war mir eben irgendwie unklar, ich dachte eigentlich dass dort nur die Objekt ID Übergeben (Quasi der Block) wird! Ich werds ausprobieren und mich wieder melden! Schönen Tag noch! Grüße Manu ------------------ Etwaige Rechtschreibfehler sind gewollt und dienen der allgemeinen Belustigung Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
ManuelKuhn Mitglied Techniker und DvD :-)
Beiträge: 100 Registriert: 23.03.2005 Intel XEON W3503 @ 2.4GHz 8 GB DDR3 NVIDIA QUADRO FX3800 WinXP Prof SP3 x64 ACAD 2007 + ProSteel 17.2/ 18 ACAD 2010 + ProSteel V8i S3 Rhino 3D V4 Autodesk VIZ-2006 Max2011 Design Visual Studio 2008
|
erstellt am: 31. Mrz. 2011 08:34 <-- editieren / zitieren --> Unities abgeben:
Hallo zusammen, habe das ganze hinbekommen, wollte nur kurz den Code posten, falls es mal jemand gebrauchen kann! Code:
Private Sub frmProbs_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim acDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim acCurDb As Database = acDoc.Database Dim AcadAttCol As AttributeCollection Dim AcadAttID As ObjectId Dim AcadAttRef As AttributeReference Dim BlockId As ObjectId Dim btr As New BlockTableRecord Dim db As Database = HostApplicationServices.WorkingDatabase Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager Dim blkRef As BlockReference = Nothing Dim btrblock As New BlockTableRecord Dim checkVal As Boolean checkVal = False tm = db.TransactionManager Try Using tr As Transaction = tm.StartTransaction() Try Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, _ OpenMode.ForRead, False), BlockTable) For Each AcadId As ObjectId In bt btr = DirectCast(tr.GetObject(AcadId, OpenMode.ForRead, False), _ BlockTableRecord) For Each BlockId In btr Dim blkrefObj As DBObject = DirectCast(tr.GetObject(BlockId, _ OpenMode.ForRead), DBObject) blkRef = TryCast(blkrefObj, BlockReference) If blkRef IsNot Nothing Then Dim btrBlockID As ObjectId = blkRef.BlockTableRecord btrblock = DirectCast(tr.GetObject(btrBlockID, _ OpenMode.ForRead), BlockTableRecord) If btrblock.Name = My.Settings.selitem Then checkVal = True GoTo Exit_For Else : End If End If Next Next Exit_For: If checkVal = True Then Me.Text = btrblock.Name AcadAttCol = blkRef.AttributeCollection Dim subObj As DBObject For Each AcadAttID In AcadAttCol subObj = DirectCast(tr.GetObject(AcadAttID, OpenMode.ForRead), _ DBObject) AcadAttRef = DirectCast(subObj, AttributeReference) If AcadAttRef Is Nothing Then MsgBox("No Attributes found!", MsgBoxStyle.Critical, "ERROR") Else gridView.Rows.Add(AcadAttRef.Tag, AcadAttRef.TextString) AcadAttRef.Dispose() End If subObj.Dispose() Next blkRef.Dispose() btrblock.Dispose() btr.Dispose() Else : End If Finally tr.Dispose() End Try End Using Finally End Try End Sub
------------------ Etwaige Rechtschreibfehler sind gewollt und dienen der allgemeinen Belustigung [Diese Nachricht wurde von ManuelKuhn am 31. Mrz. 2011 editiert.] Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
Ex-Mitglied
|
erstellt am: 31. Mrz. 2011 09:51 <-- editieren / zitieren -->
Hi, danke, dass Du den Code gepostet hast; ein gutes Beispiel für 'Sinn eines Forums voll verstanden'! Und gleich eine Korrektur (siehe es als Empfehlung, nicht als Kritik!) Ich glaube nur, dass Du bei großen DWG's ziemlich langsam sein wirst mit dem Durchscannen durch die ganze Zeichnungsdatenbank. Mein Ansatz daher grob/verbal: BlockTable durchscannen nach eine BlockDefinition mit dem gesuchten Namen Haben wir die Blockdefinition (BlockTableRecord), dann hat diese eine eigene Funktion, abgeleitete BlockReferenzen zu finden, und fertig, da bist Du schon. Code: tm = db.TransactionManagerTry Using tr As Transaction = tm.StartTransaction() Try Dim tBlRefIDs As ObjectIdCollection = Nothing Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead, False), BlockTable) For Each AcadId As ObjectId In bt 'erst mal pruefen, ob diese ObjektID nicht als 'gelöscht' markiert ist If (AcadId.IsValid) AndAlso (Not AcadId.IsErased) Then 'hier werden die Blockdefinitionen durchgescannt, um zur gesuchten BlockDefinition zu kommen btr = DirectCast(tr.GetObject(AcadId, OpenMode.ForRead, False), BlockTableRecord) If btr.Name = My.Settings.selitem Then Me.Text = btr.Name 'nun haben wir die Blockdefinition, die wir suchen 'aus dem holen wir die IDs der eingefügten BlockReferenzen tBlRefIDs = btr.GetBlockReferenceIds(False, True) Exit For End If End If Next 'und jetzt können wir die BlockReferenzen direkt durchgehen (ohne alles durchzuscannen) If (tBlRefIDs IsNot Nothing) AndAlso (tBlRefIDs.Count > 0) Then For Each tBlRefID As ObjectId In tBlRefIDs Dim tBlRef As BlockReference = CType(tr.GetObject(tBlRefID, OpenMode.ForRead), BlockReference) AcadAttCol = blkRef.AttributeCollection For Each AcadAttID In AcadAttCol AcadAttRef = DirectCast(tr.GetObject(AcadAttID, OpenMode.ForRead), AttributeReference) If AcadAttRef Is Nothing Then 'kann es eigentlich nicht sein MsgBox("No Attributes found!", MsgBoxStyle.Critical, "ERROR") 'hier solltest Du, wenn Du schon darauf pruefst, ein EXIT FOR einbauen ' sonst bekommt der User Anfälle, wenn er in einer Schleife die Meldung 1000 mal bekommt Else gridView.Rows.Add(AcadAttRef.Tag, AcadAttRef.TextString) 'das bitte nicht: AcadAttRef.Dispose() End If Next Next End If Catch ex2 As Exception MsgBox("Fehler aufgetreten (ErrPos=2)" & vbNewLine & ex2.Message) Finally 'das bitte nicht, wenn Du mit 'Using TR ...' arbeitest, dann macht das schon .Dispose ' tr.Dispose() End Try End Using Catch ex As Exception MsgBox("Fehler aufgetreten (ErrPos=1)" & vbNewLine & ex.Message) End Try
Code ungetestet, ich hab ja Deine Form-Controls nicht. Aber es geht mehr um den Sinn.
Viel Erfolg, - alfred - ------------------ www.hollaus.at |
ManuelKuhn Mitglied Techniker und DvD :-)
Beiträge: 100 Registriert: 23.03.2005 Intel XEON W3503 @ 2.4GHz 8 GB DDR3 NVIDIA QUADRO FX3800 WinXP Prof SP3 x64 ACAD 2007 + ProSteel 17.2/ 18 ACAD 2010 + ProSteel V8i S3 Rhino 3D V4 Autodesk VIZ-2006 Max2011 Design Visual Studio 2008
|
erstellt am: 31. Mrz. 2011 20:32 <-- editieren / zitieren --> Unities abgeben:
Zitat: Original erstellt von a.n.: Hi,danke, dass Du den Code gepostet hast; ein gutes Beispiel für 'Sinn eines Forums voll verstanden'! Und gleich eine Korrektur (siehe es als Empfehlung, nicht als Kritik!) Ich glaube nur, dass Du bei großen DWG's ziemlich langsam sein wirst mit dem Durchscannen durch die ganze Zeichnungsdatenbank.
Hi Alfred, danke für die "Blumen" so sollte es meiner Meinung nach auch sein! Versteh ich nicht als Kritik (wobei konstruktive Kritik immer gut ist, denn "Nobody is perfekt") ich bin immer auf der Suche, meinen Code besser und Sinnvoller zu gestalten, vorallem effektiver! Ich werds auf jeden Fall versuchen und entsprechen implementieren! Grüße Manu ------------------ Etwaige Rechtschreibfehler sind gewollt und dienen der allgemeinen Belustigung Eine Antwort auf diesen Beitrag verfassen (mit Zitat/Zitat des Beitrags) IP |
| Anzeige.:
Anzeige: (Infos zum Werbeplatz >>)
|