TheSwamp
Code Red => .NET => Topic started by: Helsinki_Dave on April 12, 2011, 08:34:39 AM
-
Hi, I was wondering if anyone has cracked this one, as I've been sitting on this since the beginning of the year - but I'm mystified.
How can I find a SINGLE value of a a property set definition - ie I don't want a list as returned by the For Each loop.
Here's the ACA supplied code - which supplies all the PropertyValueUnitPairs cleverly stored in an Arraylist.
#Region "Command_GetPropertyDataByName"
' <summary>
' Command implementation for GetPropertyDataByName.
' </summary>
<Autodesk.AutoCAD.Runtime.CommandMethod("AecPropertySampleMgd", "GetPropertyDataByName", Autodesk.AutoCAD.Runtime.CommandFlags.Modal)> _
Public Sub Command_GetPropertyDataByName()
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
' prompt for the property name
Dim res1 As PromptResult = ed.GetString(vbCrLf + "Enter Property name: ")
If res1.Status <> PromptStatus.OK Then
Return
End If
Dim pname As String = res1.StringResult
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim tm As AcadDb.TransactionManager = db.TransactionManager
Dim dbobj As AcadDb.DBObject
Dim trans As Transaction = tm.StartTransaction()
Dim bt As BlockTable = tm.GetObject(db.BlockTableId, OpenMode.ForRead, False)
Dim btr As BlockTableRecord = tm.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead, False)
Dim id As ObjectId
For Each id In btr
dbobj = tm.GetObject(id, OpenMode.ForRead, False, False)
Dim values As System.Collections.ArrayList = GetValuesFromPropertySetByName(pname, dbobj)
Dim value_unit As AecPropDb.PropertyValueUnitPair
For Each value_unit In values
ed.WriteMessage(vbCrLf + "Property with name = " + pname + " Entity ObjectId = " + id.ToString())
ed.WriteMessage(vbCrLf + "Unit Type = " + value_unit.UnitType.InternalName + ", IsImperial = " + value_unit.UnitType.IsImperial.ToString() + ", Type = " + value_unit.UnitType.Type.ToString())
Dim val As Object = value_unit.Value
If Not val Is Nothing Then
ed.WriteMessage(vbCrLf + "DataType = " + val.GetType().ToString())
ed.WriteMessage(vbCrLf + "Value = " + val.ToString())
End If
Next
Next
trans.Commit()
trans.Dispose()
End Sub
#End Region
And here's the function
#Region "GetValuesFromPropertySetByName"
' <summary>
' Returns the values (PropertyValueUnitPair) of a property by name on a given object.
' </summary>
' <param name="pname">The property name to find on the object.</param>
' <param name="dbobj">The object to find the property on. </param>
' <returns> An array of the values </returns>
Public Function GetValuesFromPropertySetByName(ByVal pname As String, ByVal dbobj As AcadDb.DBObject) As System.Collections.ArrayList
Dim setIds As ObjectIdCollection = AecPropDb.PropertyDataServices.GetPropertySets(dbobj)
Dim values As System.Collections.ArrayList = New System.Collections.ArrayList()
If setIds.Count = 0 Then
Return values ' just return emtpy collection...
End If
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim tm As AcadDb.TransactionManager = db.TransactionManager
Dim psId As ObjectId
For Each psId In setIds
Dim pset As AecPropDb.PropertySet = tm.GetObject(psId, OpenMode.ForRead, False, False) 'As AecPropDb.PropertySet
Dim pid As Integer
Try
pid = pset.PropertyNameToId(pname)
values.Add(pset.GetValueAndUnitAt(pid))
Catch e As Autodesk.AutoCAD.Runtime.Exception
' most likely eKeyNotfound.
End Try
Next
Return values
End Function
#End Region
so to acceess just a single property set def...do I have to do something wierd like...
For Each objId As ObjectId In mdlSpace
If objId.ObjectClass.Name = "AecDbSpace" Then
Dim spce As ArchDbSrvcs.Space = trx.GetObject(objId, OpenMode.ForRead)
Dim spceStyle As ArchDbSrvcs.SpaceStyle = trx.GetObject(spce.StyleId, OpenMode.ForRead)
Dim Values_Result As ArrayList = GetValuesFromPropertySetByName("Category", spce)
Dim ArrayListIndexValue As Integer = Values_Result.IndexOf("Category")
Dim value_unit As AecPropDb.PropertyValueUnitPair = Values_Result.Item(ArrayListIndexValue)
Dim val As Object = value_unit.Value
'ed.WriteMessage(vbCrLf + "DataType = " + val.GetType().ToString())
Dim CaseSelValue As String = val.ToString()
Select Case CaseSelValue
Case "Block"
thanks in advance for your help.
-
ok, well I did it. It seems that, in lay-mans terms, there's been a bit of a storm in the timber yard - and, well, the whole way of thinking about property sets and property set definitions has been re-thought on the journey from VBA to .NET . That said, the future is bright - albeit full of transactions and blocktables, just takes a long time for guys like me to get their head around it.
So here's some pretty butch code that finds a single definition, on a single property set, on a AecDbSpace. If you have the same named definition on another property set, it wont touch it, or if you have the same named definition on another object - like a AECPolygon, it won't touch it.
Pat on the back.
#Region "Namespaces"
Imports System
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.Aec.DatabaseServices
Imports Autodesk.Aec.PropertyData.DatabaseServices
Imports DBTransactionManager = Autodesk.AutoCAD.DatabaseServices.TransactionManager
Imports AcadDb = Autodesk.AutoCAD.DatabaseServices
Imports AecDb = Autodesk.Aec.DatabaseServices
Imports AecPropDb = Autodesk.Aec.PropertyData.DatabaseServices
Imports ObjectId = Autodesk.AutoCAD.DatabaseServices.ObjectId
Imports ObjectIdCollection = Autodesk.AutoCAD.DatabaseServices.ObjectIdCollection
Imports AecDbSrvcs = Autodesk.Aec.DatabaseServices
Imports ArchDbSrvcs = Autodesk.Aec.Arch.DatabaseServices
#End Region
Public Class Renumber
#Region "Command_Renumber"
' <summary>
' Command implementation for SetPropertyDataByName.
' </summary>
<Autodesk.AutoCAD.Runtime.CommandMethod("AecPropertySampleMgd", "koe", Autodesk.AutoCAD.Runtime.CommandFlags.Modal)> _
Public Sub Command_SetPropertyDataByName()
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
Dim psetname As String = "Block_properties"
Dim pname As String = "Block_ID"
Dim NewValue As Integer = 112233
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim tm As AcadDb.TransactionManager = db.TransactionManager
Dim dbobj As AcadDb.DBObject
Dim trans As Transaction = tm.StartTransaction()
Dim bt As BlockTable = tm.GetObject(db.BlockTableId, OpenMode.ForRead, False)
Dim btr As BlockTableRecord = tm.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead, False)
Dim id As ObjectId
For Each id In btr
If id.ObjectClass.Name = "AecDbSpace" Then
dbobj = tm.GetObject(id, OpenMode.ForRead, False, False)
Dim spobj As ArchDbSrvcs.Space = tm.GetObject(id, OpenMode.ForRead, False, False)
Dim spceStyle As ArchDbSrvcs.SpaceStyle = tm.GetObject(spobj.StyleId, OpenMode.ForRead, False, False)
If spceStyle.Name = "Block" Then
'Dim values As System.Collections.ArrayList = GetValueFromPropertySetByName(psetname, pname, dbobj)
'Dim value_unit As AecPropDb.PropertyValueUnitPair
'For Each value_unit In values
' Dim currentValue As Object = value_unit.Value
' If Not currentValue Is Nothing Then
' If (currentValue.GetType() Is GetType(Double)) Then
Dim trans2 As Transaction = tm.StartTransaction()
dbobj.UpgradeOpen()
Dim WasChanged As Boolean = SetValueFromPropertySetByName(psetname, pname, dbobj, NewValue)
If WasChanged Then
ed.WriteMessage(vbCrLf + "Succesfully changed value for objectId = " + id.ToString())
ed.WriteMessage(vbCrLf + " New Value = " + NewValue.ToString())
Else
ed.WriteMessage(vbCrLf + "Failed to change value for objectId = " + id.ToString())
End If
trans2.Commit()
trans2.Dispose()
' End If
'End If
End If
End If
Next
'Next
trans.Commit()
trans.Dispose()
End Sub
#End Region
#Region "SetValueFromPropertySetByName"
' <summary>
' Sets the values (PropertyValueUnitPair) of a property by name on a given object.
' </summary>
' <param name="pname">The property name to find on the object.</param>
' <param name="dbobj">The object to set the property on. </param>
' <param name="value">The value to set. </param>
' <returns> true if succesful, or false otherwise. </returns>
Public Function SetValueFromPropertySetByName(ByVal psetname As String, ByVal pname As String, ByVal dbobj As AcadDb.DBObject, ByVal NewValue As Object) As Boolean
Dim findany As Boolean = False
Dim setIds As ObjectIdCollection = AecPropDb.PropertyDataServices.GetPropertySets(dbobj)
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim tm As AcadDb.TransactionManager = db.TransactionManager
Dim trans As Transaction = tm.StartTransaction()
Dim psId As ObjectId
For Each psId In setIds 'setids is all property sets
Dim pset As AecPropDb.PropertySet = tm.GetObject(psId, OpenMode.ForWrite, False, False) ' As AecPropDb.PropertySet
If pset.PropertySetDefinitionName = psetname Then
Dim pid As Integer 'have to create this object to place the PropertyNameToId somewhere
pid = pset.PropertyNameToId(pname) 'propertynametoid gives the id for the psetdef
If (pset.IsWriteEnabled) Then
pset.SetAt(pid, NewValue)
End If
findany = True
'esential findany changes the value of the function
End If
Next
trans.Commit()
trans.Dispose()
Return findany
End Function
#End Region
End Class