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. Better, with the Revit Element Data Extension, things will be more convenient and natural.
Here is the Revit Element Data Extension:
using System;
using System.Xml.Serialization;
using System.IO;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage; //Revit API 2012 only
namespace RevitAddinWizard
{
public static class ElementDataExtension
{
private const string SingleStringFiledName = "SingleStringForAll";
public static void SetData(this Element e, string id, object o)
{
SchemaBuilder sb = new SchemaBuilder(new Guid(id));
sb.SetSchemaName(id.Replace("-", ""));
FieldBuilder fb = sb.AddSimpleField(SingleStringFiledName, typeof(string));
XmlSerializer xml = new XmlSerializer(o.GetType());
using (StringWriter w = new StringWriter())
{
xml.Serialize(w, o);
Entity ent = new Entity(sb.Finish());
ent.Set<string>(SingleStringFiledName, w.ToString());
e.SetEntity(ent);
}
}
public static T GetData<T>(this Element e, string id)
{
Schema sch = Schema.Lookup(new Guid(id));
string s = e.GetEntity(sch).Get<string>(SingleStringFiledName);
XmlSerializer xml = new XmlSerializer(typeof(T));
using (StringReader r = new StringReader(s))
{
return (T)xml.Deserialize(r);
}
}
}
}
Let us see how to store some data of type ElementId into a picked Element, read the data back, and do something to the Element to which the ElementId points.
Readers might think of it is necessary to create a wrapper for the ElementId type as we did to the XYZ and UV types since either Revit Element Data Extension or Revit Data Operator does not support the ElementId type directly. It will work definitely. However, for the particular ElementId case, things do not necessarily have to go that far as the ElementId is nothing more than an integer value actually.
Therefore, we can store the integer value of the ElementId into the picked Element using either the Revit Element Data Extension or Revit Data Operator. When reading the value back, we can easily reconstruct the ElementId from the integer.
Here is the test code to write an ElementId value to a selected Element:
Reference picked = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick a window");
Reference picked1 = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick an element to store its ElementId into the window");
using (Transaction trans = new Transaction(CachedDoc, "AttachDataTo"))
{
trans.Start();
CachedDoc.GetElement(picked).SetData("DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F", CachedDoc.GetElement(picked1).Id.IntegerValue );
trans.Commit();
}
As can be seen, the code of real concern is only on line!
Here is the code to read back the ElementId data from the same Element and get the Element that the ElementId points to zoomed in:
Reference picked = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick the window having our data");
using (Transaction trans = new Transaction(CachedDoc, "ReadDataFrom"))
{
trans.Start();
ElementId id = new ElementId(CachedDoc.GetElement(picked).GetData<int>("DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F"));
if (id == ElementId.InvalidElementId) // To verify the element id
MessageBox.Show("The read-back id is wrong!");
else
CachedUiApp.ActiveUIDocument.ShowElements(id);
trans.Commit();
}
As can be seen again, the code of real concern regarding ElementId extraction and reconstruction is still one line long! If the above test code is put into an external command, we can happily verify that the Element could be zoomed in successfully.
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, 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.
Life is becoming easier and easier, cooler and cooler. Huh?
The Revit Addin Wizard (RevitAddinWizard) is going to provide a coder to help generate Extensible Storage code.
Recent Comments