有客户报了一个问题,说用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的元素,也会造成相同的问题。
所以,以后遍历文档的时候,大家需要注意哦。