Как получить все уровни, упорядоченные по высоте
Вопрос: Как я могу получить коллекцию уровней, отсортированную по высоте уровня? Пока что мне кажется, что FilteredElementCollector возвращает IEnumerable и его можно отсортировать с помощью OrderBy, затем, вызвав метод ToElementIds(), то будет создан набор идентификаторов, в уже нужном порядке. Верно?
Вот код, который я попробовал. Он не работает:
- UIDocument uiDoc = this.ActiveUIDocument;
- Document doc = uiDoc.Document;
- FilteredElementCollector levCollector
- = new FilteredElementCollector( doc );
- ICollection<Element> levelsCollection
- = levCollector.OfClass( typeof( Level ) )
- .OrderBy( lev => lev.Elevation )
- .ToElementIds();
Кто-то может мне подсказать, что я делаю не так?
Ответ 1: Я не разбирался с остальным кодом, но я по крайней мере вижу, что если вы определяете переменную как ICollection<Element>, то эту коллекцию нужно заполнять объектами типа Element, а не ElementId:
- ICollection<Element>... .ToElementIds();
Ответ 2:
- static IOrderedEnumerable<Level> FindAndSortLevels(
- Document doc )
- {
- return new FilteredElementCollector( doc )
- .WherePasses( new ElementClassFilter( typeof( Level ), false ) )
- .Cast<Level>()
- .OrderBy( e => e.Elevation );
- }
Ответ 3: Нужно заменить вот эту часть:
- ICollection<Element> levelsCollection
- = levCollector.OfClass( typeof( Level ) )
- .OrderBy( lev => lev.Elevation )
- .ToElementIds();
На вот эту:
- List<Level> levelsCollection
- = levCollector.OfClass( typeof( Level ) )
- .OfType<Level>()
- .OrderBy( lev => lev.Elevation )
- .ToList();
Причины:
- Возвращаемое значение не может быть ICollection<Element> если вызывается метод ToElementIds()
- Метод OfClass() возвращает коллекцию объектов типа Element, поэтому вы можете отсортировать их по высоте (Elevation), только после приведения к типу Level. Поэтому я и предложил использовать OfType<Level>().
- Метод OrderBy возвращает IOrderedEnumerable<T> и если вы хотите обращаться к объектам коллекции по индексу, т.е. list[i], то нужно вызвать метод ToList(), который вернет List<T>
Ответ 4: Дополнения от Jeremy:
Использование методов класса FilteredElementCollector для предварительной фильтрации элементов всегда предпочтительней, чем явное использование ElementFilter, так как в этом случае будут гарантировано использоваться так называемые «быстрые» фильтры. Поэтому и было предложено сначала использовать OfClass( typeof( Level ) ) для явного использования ElementClassFilter.
Класс FilteredElementCollector уже сам по себе является перечисляемой коллекцией. Поэтому зачастую не нужно дополнительно создавать коллекции .NET, более подробно можно почитать в статье Оптимизация поиска элементов (на англ.)
Вот моя реализация:
- As a result of those considerations, here is my suggestion for an optimal solution:
- IOrderedEnumerable<Level> GetSortedLevels( Document doc )
- {
- return new FilteredElementCollector( doc )
- .OfClass( typeof( Level ) )
- .Cast<Level>()
- .OrderBy( lev => lev.Elevation );
- }
Еще множество примеров по использованию FilteredElementCollector, смотрите в примерах The Building Coder, в модуле CmdCollectorPerformance.cs.
Источник: http://thebuildingcoder.typepad.com/blog/2014/11/webgl-goes-mobile-and-sorted-level-retrieval.html
Обсуждение: http://adn-cis.org/forum/index.php?topic=1118
Опубликовано 29.11.2014