RevitAPI:不要在遍历(Iterate)过滤出来的收集器(FilteredElementCollector)时修改文档(Document)

来源:互联网 发布:编译c语言的软件 编辑:程序博客网 时间:2024/06/06 04:41

有客户报了一个问题,说用API加载族(Familly)的时候,如果这个文件是一个新的文件,那不会出现问题,但是如果是升级文件,Revit就会崩溃。

他的代码大概是这样的:

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);}

首先过滤出来所有的族Family,然后去本地路径里面搜索对应于这个族的.rfa文件,然后调用Document.LoadFamily来Load这个.rfa文件。

我试着在每次调用ReloadFamily之前,输出对应的elem的Id和名字,

while (itr.MoveNext()){    Element elem = (Element)itr.Current;    WriteLog(elem.Id + ":" + elem.Name);    ReloadFamily(rvtApp, rvtDoc, elem);}

输出之后发现,有的Id会出现两次,而且出现两次之后,Revit就崩溃了。

那么一定是这个“两次”造成的问题。

思考是不是collector里面的元素有重复呢?重写代码把所有的elem的id都打印出来,发现并没有重复。

又试了另外一种办法,不是用Iterator,而是使用foreach,

foreach (var elem in collector.ToElements()){    ReloadFamily(rvtApp, rvtDoc, elem);}

发现Revit不会崩溃,程序可以正常跑通了。

聪明的读者一定知道foreach一定不会对结果产生影响,而是这里的ToElements()方法,该方法创建了一个新的集合。

原因已经浮现,那就是我们在遍历collector的同时,对Document进行了修改,正是这个修改造成了Revit的崩溃。

举个简单的例子,看下面的代码:

List<int> ids = new List<int>() { 1, 2, 3, 4 };foreach (int id in ids){    ids.Add(5); //Exception!!!}
当我们遍历ids的时候,对ids本身进行添加或者删除元素的操作会抛异常:

System.InvalidOperationException: 集合已修改;可能无法执行枚举操作。

同样的道理,对Revit文档进行遍历操作的时候,增加或删除Revit的元素,也会造成相同的问题。

所以,以后遍历文档的时候,大家需要注意哦。


0 0