Family Category and Filtering
So here we are in a brand new year, 2009. Welcome back! Here is an interesting question regarding families, their categories, and filtering, raised last year by Martin Schmid of Autodesk.
Question: In the following code, I attempt to use Revit API filtering to select all families with a built-in category value of BuiltInCategory.OST_MechanicalEquipment:
Document doc = app.ActiveDocument; List<Element> famsInCat = new List<Element>(); Autodesk.Revit.Creation.Filter cf = app.Create.Filter; TypeFilter typeFilter = cf.NewTypeFilter( typeof( Family ) ); CategoryFilter catFilter = cf.NewCategoryFilter( bic ); LogicAndFilter andFilter = cf.NewLogicAndFilter( typeFilter, catFilter ); doc.get_Elements( andFilter, famsInCat ); return famsInCat;
Unfortunately, this does not work as expected, even when some mechanical equipment families have been loaded into the model.
Instead, this more cumbersome iterative approach can be used successfully:
Category categoryMechanicalEquipment = doc.Settings.Categories.get_Item( bic ); ElementId categoryId = categoryMechanicalEquipment.Id; ElementIterator it = doc.get_Elements( typeof( Family ) ); while( it.MoveNext() ) { Family family = it.Current as Family; bool categoryMatches = family.FamilyCategory.Id.Equals( categoryId ); if( categoryMatches ) { famsInCat.Add( family ); } } return famsInCat;
Do you see any errors in my logic?
Answer: The reason it does not work is because the Family class does not implement the Category property for all family files. Although the property is provided by the Family class, it sometimes returns null. The filter is probably using this property internally, but to no avail.
Therefore, you have to use some other method to check the category of a family. On some family instances, you can use FamilyCategory instead of Category, like you are doing in your working code snippet. Unfortunately, even this work-around is not reliable for all families. On some families, the FamilyCategory property is not implemented either. The most reliable method is to check the Category property on any one symbol contained in the family. Mostly, it is practical to just use the first symbol defined in the family. Here is some updated code demonstrating this approach:
Category categoryMechanicalEquipment = doc.Settings.Categories.get_Item( bic ); ElementId categoryId = categoryMechanicalEquipment.Id; ElementIterator it = doc.get_Elements( typeof( Family ) ); while( it.MoveNext() ) { Family family = it.Current as Family; foreach( Symbol s in family.Symbols ) { if( s.Category.Id.Equals( categoryId ) ) { famsInCat.Add( family ); } break; // only need to look at first symbol } } return famsInCat;
Unfortunately, as Martin points out above, this does indeed mean that you have to add some own slightly cumbersome code after the filtered element retrieval to check for the desired category.

Subscribe
Hi Jeremy,
Is it possible to trigger the Property Dialog of a Family through API (to show it)? I'm afraid not but I ask ;-). Would be cool not have to program it again.
Roozbeh
Posted by: Rooz | April 08, 2009 at 13:51
Dear Roozbeh,
Just as you suspect, the official API provides no such functionality. You might try various tricks using the Win32 API to simulate some user interaction:
http://thebuildingcoder.typepad.com/blog/2008/12/driving-revit-from-outside.html
There are also tools available that make use of this kind of technique internally and shield you from some of the nitty gritty details, such as AutoHotKey:
http://thebuildingcoder.typepad.com/blog/2009/01/autohotkey.html
Cheers, Jeremy.
Posted by: Jeremy Tammik | April 08, 2009 at 22:35
Hi Jeremy,
thanks for the answer. I tested the example code, and changed it to get a Revit App through Windows Title Bar Text but it gets tricky to get the correct Revit instance if there are more than one Revit instances active. That's why I think I would try to retrieve the parameters of my interest in a Dialog.
Best Regards
Roozbeh
Posted by: Rooz | April 10, 2009 at 08:18
Hi Roozbeh,
I am glad you were able to make some use of the code and modify it for your use. One possible way to avoid the issue of selecting the correct one out of multiple running Revit instances may be provided by making use of System.Diagnostics.Process.GetCurrentProcess. If you are inside a Revit command, that will ensure you get the instance of Revit that you are running in.
You can definitely implement an application that sits and waits and watches for a certain dialogue to pop up, and then extracts data from it. This can be achieved using a windows hook based on the CBTProc function: The CBTProc hook procedure is an application-defined or library-defined call-back function used with the SetWindowsHookEx function. The system calls this function before activating, creating, destroying, minimizing, maximizing, moving, or sizing a window.
Cheers, Jeremy.
Posted by: Jeremy Tammik | April 14, 2009 at 04:01
Thanks for pointing out the extra information Jeremy!
Regards Roozbeh
Posted by: Rooz | April 16, 2009 at 06:58