Revit API 2012 provides the ability to extend Element data officially. In the old days, we could only create some invisible parameters and attach them to the elements when we would like to store some extra data. Now the ExtensibleStorage API can directly address such very normal need and is more powerful.
It is powerful because the ExtensibleStorage API can store from the simplest data types such as integer and double to complex ones such as LIST and MAP. In this post, let us create some short code to demonstrate how to store an integer value to an element, e.g. Window.
Here is the code along with the Execute method implementation of an External Command interface:
public Result Execute(ExternalCommandData cmdData, ref string msg, ElementSet elemSet)
{
_cachedCmdData = cmdData;
try
{
//TODO: add your code below.
Reference picked = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element,"Pick a window");
using (Transaction trans = new Transaction(CachedDoc , "AttachDataTo"))
{
trans.Start();
SchemaBuilder sb = new SchemaBuilder(new Guid("DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F"));
sb.SetSchemaName("SchemaTest1");
FieldBuilder fb = sb.AddSimpleField("FieldTest1", typeof(int));
Schema schema = sb.Finish();
Entity ent = new Entity(schema);
ent.Set<int>("FieldTest1", 123);
CachedDoc.GetElement(picked).SetEntity(ent);
trans.Commit();
}
return Result.Succeeded;
}
catch (Exception ex)
{
msg = ex.ToString();
return Result.Failed;
}
}
There are only a few lines of code but quite a few classes and methods are still involved in the simplest case as can be seen. Here are some highlights:
• Start a Transaction first;
• Create a SchemaBuilder and pass a Schema Guid to it;
• Set the name for the Schema; It is needed, otherwise, the exception ‘Autodesk.Revit.Exceptions.InvalidOperationException: SchemaName is not set.’ would come up when the ExtensibleStorage.SchemaBuilder.Finish() method is called.
• Define a field with the name and type that we want into the Schema that was just built up through calling the AddSimpleField() of the SchemaBuilder and return a FieldBuilder.
• Call the Finish() method of the SchemaBuilder object to finally return the Schema we like.
• An intermediate, the Entity, between the Schema and the Element needs to be created from the Schema.
• The various Set() methods of the Entity instance are used to set the field values. Please do make the field names in the AddSimpleField() call and in the Set() method match each other.
• Call the new SetEntity() method of the Element to attach the Entity to the Element.
• Last but not least, please do not forget to commit the Transaction.
Sound quite cumbersome, huh?
Indeed, but wrappers can be created to meet different needs, from the simplest to the most demanding. We will revisit the topic a bit in the new future.
Now how do we know if the integer value 123 has been successfully attached to the Window that was picked? The following short and nice code can tell us:
Reference picked = CachedUiApp.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Pick a window");
using (Transaction trans = new Transaction(CachedDoc, "ReadDataFrom"))
{
trans.Start();
Schema sch = Schema.Lookup(new Guid("DA4AAE5A-4EE1-45A8-B3E8-F790C84CC44F"));
Entity ent = CachedDoc.GetElement(picked).GetEntity(sch);
int ret = ent.Get<int>("FieldTest1");
MessageBox.Show(ret.ToString());
trans.Commit();
}
If the above code is put into another External Command, when it runs and the same Window is picked, the value will be properly reported back in a message box:
The code looks simple again but still a few points deserve to be mentioned:
• If the Schema has already built up in your application or even somewhere not under your control, the static Lookup method of the Schema should be used to retrieve the same Schema back.
• In this case, the single same identifier is sufficient to look up the Schema that we built up in the other command. The Schema name is no use here though we were forced to give one at that moment.
• If we build up the Schema the same way as in the first command instead of looking it up, an exception saying ‘Autodesk.Revit.Exceptions.InvalidOperationException: A different Schema with the same identity already exists.’ would appear.
• Now the counterpart method to the SetEntity(), GetEntity(), of the same Element can be called to retrieve back the same Entity.
• The various Get generic methods of the Entity can be used to return different values to us from their field names.
• Transaction is still necessary as usual, if the TransactionMode is Manual.
The Revit Addin Wizard (RevitAddinWizard) is going to provide a coder to help generate ExtensibleStorage code.
Recent Comments