cp4451 Tammik Estorage
cp4451 Tammik Estorage
cp4451 Tammik Estorage
Learning Objectives
At the end of this class, you will be able to:
Understand the underlying concepts and real-world techniques for working with extensible storage.
Programmatically create a schema; read, update, and delete extensible storage data on elements.
Handle versioning issues when upgrading and extending an existing extensible storage schema.
Extract and display extensible storage data and serialize and de-serialize schemas to XML.
Contents
What is Extensible Storage? ..................................................................................... 2
Evolution of Storage Options .................................................................................... 2
Shared Parameters versus Estorage ........................................................................ 3
Estorage Basics ........................................................................................................ 3
Units ..................................................................................................................... 4
Examples ................................................................................................................... 4
Estorage of a Simple XYZ Point .......................................................................... 4
List Loaded Schemata ......................................................................................... 6
Determine Estorage Use in Document ................................................................ 6
Estorage of Complex Data ................................................................................... 7
Estorage Deletion ................................................................................................. 8
Storing a File on a Revit Element ........................................................................ 8
Additional Observations ............................................................................................ 9
Sample Applications ................................................................................................ 11
FamilyStorage .................................................................................................... 11
UpgradeSchema ................................................................................................ 11
Dynamic Section View ....................................................................................... 12
Schema Wrapper Tools ..................................................................................... 13
Extensible Storage Manager .............................................................................. 13
Related Blog Posts .................................................................................................. 13
Acknowledgements ................................................................................................. 13
Appendix: Hands-on Lab Instructions ..................................................................... 14
Revit SDK ........................................................................................................... 14
Visual Studio Add-in Wizards ............................................................................. 14
Hands-on Exercises ........................................................................................... 14
2
Extensible Storage in the Revit 2012 API
It makes use of a schema, which is a class-like definition specifying the data types and structure of the data
to store. The schema contains a list of fields, each of which specifies a name, data type, unit type, and
description. The schema is associated with read/write permissions.
The actual data is stored in an entity class, an instance of a schema filled with data.
Each Revit element can store one or more entity instances of different schemata.
Estorage Basics
Estorage thus allows you to create your own class-like schema data structures and attach instances of
them to any element in a Revit model, and can be used to replace the technique of storing data in hidden
shared parameters. Schema-based data is saved with the Revit model and allows for higher-level,
metadata-enhanced, object-oriented data structures. Schema data can be configured to be readable and/or
writable to all users, just a specific application vendor, or just a specific application from a vendor. The
extensible storage classes are all found in the Autodesk.Revit.DB.ExtensibleStorage namespace:
Schema contains a unique schema identifier, read/write permissions, and a collection of data Field
objects.
SchemaBuilder create Schema definitions.
Field contains data name, type, and unit information and is used as the key to access
corresponding data in an Entity.
FieldBuilder a helper class used with SchemaBuilder when creating a new field.
Entity an object containing data corresponding to a Schema that can be inserted into a Revit
Element.
The following data types are supported:
bool, short, int, float, double
string
Guid
ElementId
Autodesk.Revit.DB.UV
Autodesk.Revit.DB.XYZ
Array (as a System.Collections.Generic.IList<T>)
Map (as a System.Collections.Generic.IDictionary<TKey, TValue> all types are supported for keys
except double, float, XYZ, and UV)
Autodesk.Revit.DB.ExtensibleStorage.Entity (an instance of another Schema, also known as a
SubSchema)
Addition of these data types and structures to a schema are supported by three SchemaBuilder methods
AddSimpleField( string name, Type ): Creates a field containing a single value in the schema, with
given name and type.
3
Extensible Storage in the Revit 2012 API
AddArrayField( string name, Type ): Creates a field containing an array of values in the schema, with
given name and type of contained values.
AddMapField( string name, Type keyType, Type valueType ): Creates a field containing an ordered
key-value map in the schema, with given name and type of contained values.
They return a FieldBuilder instance, which allow you to specify further properties such as units and
documentation for each data item.
Units
All floating-point fields (float, double, XYZ, UV and containers of these values) require a unit type (length,
temperature, etc.). Conversely, all other field types may not have units. As stated in the documentation,
estorage stores everything in metric for floating point type fields, but you never need to do any conversions
on your side. If you want to store a double value in feet, for example, you specify UT_Length in
FieldBuilder.SetUnitType, and DUT_DECIMAL_FEET when calling Entity.Set and Entity.Get.
Examples
The class materials include the following commands demonstrating examples of basic estorage usage:
StoreSimple estorage of a simple XYZ point
List list all storage schemata in memory
StoreMap estorage of complex data, a string map
Delete deletion of existing storage data
StoreFile storage of arbitrary file data on a selected element
schemaBuilder.SetReadAccessLevel(
4
Extensible Storage in the Revit 2012 API
AccessLevel.Public );
schemaBuilder.SetWriteAccessLevel(
AccessLevel.Vendor );
schemaBuilder.SetVendorId( "TBC_" );
fieldBuilder.SetUnitType( UnitType.UT_Length );
schemaBuilder.SetSchemaName( "WireSpliceLocation" );
schema = schemaBuilder.Finish();
}
wall.SetEntity( entity );
5
Extensible Storage in the Revit 2012 API
If the vendor id of the add-in manifest does not match the schema vendor id, an exception is thrown by the
call to wall.SetEntity( entity ): "Writing of Entities of this Schema is not allowed to the current add-in. A
transaction or sub-transaction was opened but not closed. All changes to the active document made by
External Command will be discarded."
int n = schemas.Count;
Debug.Print(
string.Format( "{0} schema{1} defined:",
n, PluralSuffix( n ) ) );
n = fields.Count;
Debug.Print(
string.Format( "Schema '{0}' has {1} field{2}:",
s.SchemaName, n, PluralSuffix( n ) ) );
6
Extensible Storage in the Revit 2012 API
IList<Schema> schemas = Schema.ListSchemas();
IEnumerable<Element> elements
= Util.GetAllElements( doc ).ToElements();
if( entity.IsValid() )
{
return true;
}
}
}
return false;
}
This is an example of using these methods:
if( !StorageExistsQuick() )
{
Debug.Print( "None of the open documents "
+ "contains any exstensible storage data." );
}
else
{
UIApplication uiapp = commandData.Application;
Application app = uiapp.Application;
DocumentSet docs = app.Documents;
int n = docs.Size;
7
Extensible Storage in the Revit 2012 API
entity.Set<IDictionary<string, string>>(
field, stringMap );
The rest of the code remains unchanged from above.
Estorage Deletion
You can delete an individual schema entity from a Revit element using the Element.DeleteEntity method.
The UpgradeSchema sample discussed at the end demonstrates its use. To completely delete the schema
itself and all its associated data, the Schema class static method EraseSchemaAndAllEntities takes a
schema as an argument, erases all entities corresponding to it from all open documents, and erases the
schema from memory. This allows users to control the amount of memory consumed by estorage data.
Obviously, this method cannot erase the schemata from closed documents, so if a closed document
contains entities of an erased schema, opening it will reintroduce it into memory.
Besides the schema argument, the method takes a Boolean argument enabling deletion of schema entities
that an add-in normally would not have write permission for. Set this flag to true only if the user gave explicit
permission to destroy the schema.
bool overrideWriteAccessWithUserPermission
= Question( "Also delete Entities that you"
+ " have no write permission to?" );
Schema.EraseSchemaAndAllEntities( schema,
overrideWriteAccessWithUserPermission );
}
fieldBuilder = schemaBuilder.AddSimpleField(
"Folder", typeof( string ) );
fieldBuilder = schemaBuilder.AddArrayField(
"Data", typeof( byte ) );
8
Extensible Storage in the Revit 2012 API
e.SetEntity( entity );
To complete the round trip, here are the steps to restore a file from estorage data saved on a selected Revit
element e:
Entity ent = e.GetEntity( schema );
Additional Observations
Now that we have covered the basics and more, here is a list of some noteworthy storage features and
background information, partly in the form of questions and answers, e.g. on the handling of large amounts
of data and element ids.
9
Extensible Storage in the Revit 2012 API
3. Estorage is Self-documenting
When you create a schema, you are creating documentation. Be sure to fill out the documentation strings
for each field they will help you in your development process and others when they use your schema.
What's more, since you can look up a schema by Guid, if you want to share a document with a schema with
someone else, all they need is the Guid to look it up and read your structure and documentation comments.
This might be a good opportunity to either use the SchemaWrapperTools included with the
ExtensibleStorageManager SDK sample (or a simpler, similar tool) to print out a schema's field definitions
and documentation strings from a single GUID input.
5. Read/Write Permissions
This is another area that goes beyond shared parameters. While your schema definition is public, you can
restrict who reads and writes schema data based to a specific vendor or a specific application from that
vendor.
10
Extensible Storage in the Revit 2012 API
It does not. Instead, it returns a valid entity pointing to a null schema. To handle this, I expanded my check
to this:
if( null == ent || null == ent.Schema ) ...
Answer: Use the Entity.IsValid method to check to see if the entity you received from GetEntity actually
has data of a given schema.
Sample Applications
Here are a few complete sample applications demonstrating more advanced estorage topics:
FamilyStorage store data in a family file and use it when inserted into a project.
UpgradeSchema manage schema versioning and upgrading.
Dynamic Section View simple, practical use of storing an XYZ point.
ExtensibleStorageManager in-depth example to manage, share, and store schemas including
generic schema wrapping and data display.
FamilyStorage
The FamilyStorage sample shows how to create estorage in a family document and retrieve its data in a
project containing an instance of that family. It defines two external commands to implement this,
AddDataToFamily and GetFamilyData.
AddDataToFamily defines a simple estorage schema and adds an entity for it to the family itself, accessed
through the document OwnerFamily property:
Family documentFamily = doc.OwnerFamily;
Entity newEntity = MakeEntity( new XYZ( 1, 2, 3 ) );
documentFamily.SetEntity( newEntity );
GetFamilyData retrieves the stored data from the family by asking each family instance for its family:
Family family = familyInstance.Symbol.Family;
Entity entity = family.GetEntity( schema );
To test this, start by creating a new family and run the command AddDataToFamily. Note that the schema
GUID is stored in a separate class. Save the document. Create a new project and insert an instance of the
family into it. Run the command GetFamilyData.
UpgradeSchema
The UpgradeSchema sample defines an external application and command demonstrating a simple
estorage upgrade scenario, i.e. maintenance and migration of estorage data from an old version of a data
schema to an enhanced updated version.
The two schemata involved are labelled v1 and v2. The sample application implements an external
command which adds data for schema v1 to all walls in the document.
11
Extensible Storage in the Revit 2012 API
Furthermore, it implements an external application which does two things: create a ribbon panel to launch
the command, and subscribe to the DocumentOpened event. In the event handler, all elements with v1
schema entities attached to them are retrieved and their data is automatically updated to schema v2.
Here are steps to use it:
Build and install the application.
Create a document with a few walls. Save, close, and re-open it.
Note that the event looking for elements containing entities of schema v1 does not find any yet.
Click the command button to add entities of schema v1 to each wall. Save and close.
Reopen the document, and note how:
o We only need to create schema v2 schema v1 is already saved and does not need to be re-
created.
o Elements containing entities of schema v1 are found, data is copied into new entities of schema
v2, and original data is deleted.
To find elements with a specific schema entity attached to them, we iterate over a given element set and
query each for valid entity of that schema:
foreach( Element e in collector )
{
Entity entity = e.GetEntity( schema );
if( entity.IsValid() )
{
retval.Add( e.Id );
}
}
Deleting the old schema data and adding the new is straightforward, and uses the DeleteEntity method:
Entity oldEntity = element.GetEntity( oldSchema ); // v1
Entity newEntity = new Entity( newSchema ); // v2
12
Extensible Storage in the Revit 2012 API
Acknowledgements
I thank Steven Mycynek for his ideas, support, and material, and my ADN DevTech colleagues for being
such a great team to work with.
13
Extensible Storage in the Revit 2012 API
Revit SDK
The most important content in the Revit SDK for our purposes is the API documentation, which you require
to complete the exercises. It also includes a hundred-odd sample applications, a Visual Studio solution to
compile them all, and two important utilities that you should be aware of:
Revit API help file "RevitAPI.chm"
Developer guide "Revit 2012 API Developer Guide.pdf"
Visual Studio solution for all samples "SDKSamples2012.sln"
RevitLookup interactively explore the Revit database
RvtSamples load and launch all Revit SDK samples
I advise you to set up shortcuts on your desktop for the help file and the developer guide right away.
Precompiled versions of RevitLookup and RvtSamples are provided in the \Estorage\Addins folder. These
can be copied to the Revit Addins folder on your system as described in the developer guide section 3.4.1
Manifest Files.
Hands-on Exercises
The hands-on exercises correspond to the sample commands discussed above, so please refer to those
descriptions for further details and background information on their functionality.
The actual exercise for you to complete consists of fleshing out the code in the regions marked by a
comment starting with // Todo: . In general, the comment will mention what Revit API method you need to
use and what arguments to supply to it:
14
Extensible Storage in the Revit 2012 API
For further details on what these methods do and how to use them, please refer to the explanations in the
Revit API help file RevitAPI.chm and the developer guide "Revit 2012 API Developer Guide.pdf", both of
which are part of the Revit SDK.
To start working on a new exercise, select File > New > Project in Visual Studio:
The C# modules are pre-populated with the code to define an external command completing most of the
required actions. The most pertinent code statements relating to estorage have been removed, and it is
your job to find out how they should be implemented to make it work again. Look for the todo comments
such as this one:
// Todo: Use the AddSimpleField method on the
// schema builder to create a field named
// "WireSpliceLocation" to store an XYZ
// data item
15
Extensible Storage in the Revit 2012 API
In general, the external command of the exercise cannot be executed successfully without completing the
exercise, because some object initialisation code is part of the exercise. Some objects are initialised to null,
and it is you task to assign an appropriate value to them. Here is an example of an exception being thrown
in an uncompleted exercise:
To fix this, simply follow the instruction in the todo comments, referring to the Revit API help file, developer
guide, the handout description of the storage sample commands, and, if all else fails, the solved versions of
the exercises or the completed estorage sample application code.
Good luck, keep at it, and above all have fun!
16