List Railing Types
This is in response to a query from Berria on iterating over the railing types in the model. It is also once again about teaching how to fish, and not just feeding people, at least I hope so. If I want to list all the railing types, the best way to go is probably to define an API filter which retrieves them from the model for me. How do I design that filter? I start by opening a new model, inserting a railing, and examining it with RvtMgdDbg. There I can easily determine that its built-in category is OST_StairsRailing. Therefore, I first thought that an API filter selecting all family symbols of this category should suffice. The project browser shows me the following stair and railing symbols in my current model:
I implemented a new external command CmdListRailingTypes to test this approach, with the following code:
Application app = commandData.Application; Document doc = app.ActiveDocument; CreationFilter cf = app.Create.Filter; List<Element> symbols = new List<Element>(); BuiltInCategory bic = BuiltInCategory.OST_StairsRailing; Filter f1 = cf.NewCategoryFilter( bic ); Filter f2 = cf.NewTypeFilter( typeof( FamilySymbol ) ); doc.get_Elements( f, symbols ); foreach( FamilySymbol s in symbols ) { Debug.Print( "Family name={0}, symbol name={1}", s.Family.Name, s.Name ); } return CmdResult.Failed;
It makes use of a new alias for CreationFilter:
using CreationFilter = Autodesk.Revit.Creation.Filter;
To my initial surprise, no symbols were found. I thereupon took a closer look at the symbols within the railings family in RvtMgdDbg and discovered that the category of the M_Baluster symbols is not OST_StairsRailing but OST_StairsRailingBaluster. Changing the value of the 'bic' variable to that built-in category returns some valid results:
Family name=M_Baluster - Square, symbol name=25mm Family name=M_Baluster - Square, symbol name=20mm Family name=M_Baluster - Round, symbol name=25mm Family name=M_Baluster - Round, symbol name=20mm
This does still not include all the railing symbols listed in the browser, so I went back into RvtMgdDbg and searched for those as well. They were not listed in the FamilySymbol collection, but under Symbols, this time indeed with the category OST_StairsRailing.
Making use of this info, I implemented a second filter and iteration to retrieve and list Symbol objects like this:
bic = BuiltInCategory.OST_StairsRailing; f1 = cf.NewCategoryFilter( bic ); f2 = cf.NewTypeFilter( typeof( Symbol ) ); f = cf.NewLogicAndFilter( f1, f2 ); doc.get_Elements( f, symbols ); n = symbols.Count; Debug.Print( "{0}" + " OST_StairsRailing symbol{1}:", n, Util.PluralSuffix( n ) ); foreach( Symbol s in symbols ) { FamilySymbol fs = s as FamilySymbol; Debug.Print( "Family name={0}, symbol name={1}", null == fs ? "<none>" : fs.Family.Name, s.Name ); }
The result of this code is somewhat surprising too. The non-family symbols that we are looking for are retrieved now, just like we hoped, and we also retrieve the family symbols that we already saw above:
6 OST_StairsRailing symbols: Family name=M_Baluster - Square, symbol name=25mm Family name=M_Baluster - Square, symbol name=20mm Family name=M_Baluster - Round, symbol name=25mm Family name=M_Baluster - Round, symbol name=20mm Family name=<none>, symbol name=900mm Pipe Family name=<none>, symbol name=900mm Rectangular
This goes to show several things:
- You need to explore the model.
- You may get unexpected results.
I'll just leave it at that for now.
Here is version 1.0.0.25 (file no longer available) of the complete Visual Studio solution with the new CmdListRailingTypes command implementation.