The Revit API 2012 provides an official way to extend the Element data now. In the old days, we could only create some cumbersome invisible parameters and attach them to the elements where we want to store some extra data. Now the Extensible Storage API can directly address so basic a need for us and has much power.
However, as introduced and demonstrated before, unnecessary complexities, impositions, redundancies and inconsistencies are here and there. In case any of those points as mentioned repeatedly in early posts slips out of our minds, the data storage or retrieval would just fail. In addition, the out-of-box supported data types are just a few, far less than enough.
Things become super easy and cool with the Revit Data Operator. However, the first version of the Revit Data Operator does not support Dictionary type directly. Fortunately, the second version of the Revit Data Operator has got rid of the limitation, and it actually supports more types seamlessly. In this post, let us create a VB.NET version of the Revit Data Operator 2:
Imports System.Xml
Imports System.Runtime.Serialization
Imports System.IO
Imports Autodesk.Revit.DB
Imports Autodesk.Revit.DB.ExtensibleStorage 'Revit API 2012 only
Public Class SuperEasyCoolDataOperator2
Private Const SingleStringFiledName As String = "SingleStringForAll"
Public Shared Sub SetDataToElement(ByVal id As String, ByVal o As Object, ByVal e As Autodesk.Revit.DB.Element)
Dim sb As New SchemaBuilder(New Guid(id))
sb.SetSchemaName(id.Replace("-", ""))
Dim fb As FieldBuilder = sb.AddSimpleField(SingleStringFiledName, GetType(String))
Dim serializer As New DataContractSerializer(o.[GetType]())
Using ms As New MemoryStream()
serializer.WriteObject(ms, o)
ms.Seek(0, SeekOrigin.Begin)
Using reader As New StreamReader(ms)
Dim ent As New Entity(sb.Finish())
ent.[Set](Of String)(SingleStringFiledName, reader.ReadToEnd())
e.SetEntity(ent)
End Using
End Using
End Sub
Public Shared Function GetDataFromElement(Of T)(ByVal id As String, ByVal e As Autodesk.Revit.DB.Element) As T
Dim sch As Schema = Schema.Lookup(New Guid(id))
Dim s As String = e.GetEntity(sch).[Get](Of String)(SingleStringFiledName)
Dim serializer As New DataContractSerializer(GetType(T))
Using reader As XmlReader = XmlReader.Create(New StringReader(s))
Return DirectCast(serializer.ReadObject(reader), T)
End Using
End Function
End Class
Here is some test code to write/read back a Dictionary data to/from a selected Element using the VB.NET version Revit Data Operator 2:
Dim picked As Reference = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick a window to attach our data")
Using trans As New Transaction(CachedDoc, "AttachDataTo")
trans.Start()
Dim data As New Dictionary(Of String, Integer)() From {{"AAA", 111}, {"BBB", 222}, {"CCC", 333}}
SuperEasyCoolDataOperator2.SetDataToElement("DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F", data, CachedDoc.GetElement(picked))
trans.Commit()
End Using
MessageBox.Show("A dictionary has been successfully attached to the window.")
picked = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick the window having our data")
Using trans As New Transaction(CachedDoc, "ReadDataFrom")
trans.Start()
Dim data As Dictionary(Of String, Integer) = SuperEasyCoolDataOperator2.GetDataFromElement(Of Dictionary(Of String, Integer))("DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F", CachedDoc.GetElement(picked))
Dim str As String = String.Empty
Dim index As Integer = 0
For Each entry As KeyValuePair(Of String, Integer) In data
str += String.Format("Entry #{0}: {1}/{2}" & vbLf, System.Threading.Interlocked.Increment(index), entry.Key, entry.Value)
Next
MessageBox.Show(str, "MyData")
trans.Commit()
End Using
As can be seen, those complexities and impositions all go away. We do not have to specify the same schema GUIDs, scheme names, field names, data types, or unit types repeatedly. We do not have to care about all those intermediate objects such as Schema, SchemaBuilder, Field, FieldBuilder, or Entity anymore either.
What we need to care about now are what we really want, the Element itself, the data object, and the Schema identifier. If they are consistent with each other, it will be very hard to make the data storage or retrieval fail.
The Revit Addin Wizard (RevitAddinWizard) is going to provide a coder to help generate Extensible Storage code.
Recent Comments