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 slip out of our minds, the data storage or read back would just fail. In addition, the out of box supported data types are just a few, far less than enough.
For example, if we care more about the byte, ushort, long, char, decimal and DateTime types as follows, what should we do?
public class MyData
{
public byte byteVar;
public ushort ushortVar;
public long longVar;
public char charVar;
public decimal decimalVar;
public DateTime dateTimeVar;
}
In this article, let us see how this issue can be handled super easy and cool.
We create two help methods that can attach any data we like to an Element and retrieve it back with only about a dozen lines of code.
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 class SuperEasyCoolDataOperator
{
private const string SingleStringFiledName = "SingleStringForAll";
public static void SetDataToElement(string id, object o, Element e)
{
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 GetDataFromElement<T>(string id, Element e)
{
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);
}
}
}
}
Here is the test code to attach some sample data to an Element:
Reference picked = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick a window to attach our data");
using (Transaction trans = new Transaction(CachedDoc, "AttachDataTo"))
{
trans.Start();
MyData data = new MyData
{
byteVar = 255,
charVar = 'a',
ushortVar = 65535,
longVar = 1234567890,
decimalVar = 1.123456789123456789M,
dateTimeVar = new DateTime(2012, 2, 14, 23, 59, 59)
};
RevitAddinWizard.SuperEasyCoolDataOperator.SetDataToElement(
"DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F", data, CachedDoc.GetElement(picked));
trans.Commit();
}
Here is the test code to read the same data back from the same Element:
Reference picked = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick the window having our data");
using (Transaction trans = new Transaction(CachedDoc, "ReadDataFrom"))
{
trans.Start();
MyData data = RevitAddinWizard.SuperEasyCoolDataOperator.GetDataFromElement<MyData>("DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F", CachedDoc.GetElement(picked));
string str = string.Empty;
FieldInfo[] propInfoArrary = typeof(MyData).GetFields();
foreach (FieldInfo fi in propInfoArrary)
{
object obj = typeof(MyData).InvokeMember(fi.Name, BindingFlags.GetField, null, data, null);
str += string.Format("{0} : {1}\n", fi.Name, obj == null ? string.Empty : obj.ToString());
}
MessageBox.Show(str, "MyData");
trans.Commit();
}
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 data object, the Element of concern, and the Schema identifier. If they are consistent with each other, it will be very hard to make the data setting or getting fail.
Life can be so easy like this, huh?
The Revit Addin Wizard (RevitAddinWizard) is going to provide a coder to help generate Extensible Storage code.
Recent Comments