By Aaron Lu
A customer reported a problem that when loading family via API, and if the project file is an upgraded file rather than a newly created file, Revit will crash.
His code looks like this:
UIApplication rvtApp = commandData.Application; UIDocument rvtDoc = rvtApp.ActiveUIDocument; FilteredElementCollector collector = new FilteredElementCollector(rvtDoc.Document) .OfClass(typeof(Family)); FilteredElementIterator itr = collector.GetElementIterator(); while (itr.MoveNext()) { Element elem = (Element)itr.Current; ReloadFamily(rvtApp, rvtDoc, elem); }
First filter all Families, then look for corresponding .rfa file, if found, call Document.LoadFamily to load the .rfa file.
I can reproduce the problem, and tried to analyze what's wrong.
First print out the ids and names of the filtered families before calling ReloadFamily
while (itr.MoveNext()) { Element elem = (Element)itr.Current; WriteLog(elem.Id + ":" + elem.Name); ReloadFamily(rvtApp, rvtDoc, elem); }
Looking at the output, I found some ids appeard twice and then Revit crashed.
That being said, the "appear twice" is the "criminal".
I thought if there are duplicated elements in the collector which causes the "appear twice" problem. But I'm wrong, there are no duplications after some examination.
So I tried "foreach" to replace "Iterator",
foreach (var elem in collector.ToElements()) { ReloadFamily(rvtApp, rvtDoc, elem); }
And miracle happened, no crash any more.
You must know that it is not "foreach" that turns the tables but the method ToElements() which returns a new list from collector.
So the reason is obvious: while we were iterating the collector, we did change to the Document, i.e. add some new elements, which caused the crash.
Let's see a similar case for .NET collection:
List<int> ids = new List<int>() { 1, 2, 3, 4 }; foreach (int id in ids) { ids.Add(5); //Exception!!! }
We all know that when we iterate ids list, and add items to it, exception will be thrown.
Same happens to Revit Document, when we iterate elements in Document, and in the meantime, adding or deleting elements will cause Revit unstable.
Conclusion: Do not add or delete elements when iterating elements in document, unless you iterate a copy of the element or element id set.