Получить элементы спецификации в том порядке, в котором они представлены

Автор Тема: Получить элементы спецификации в том порядке, в котором они представлены  (Прочитано 3387 раз)

0 Пользователей и 2 Гостей просматривают эту тему.

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет.
Имеется спецификация. В спецификации настроены фильтры, сортировка, группировка, а также используются параметры с формулами для сортировки.
Задача - мне нужно получить все элементы, представленные в этой спецификации, а затем полученный список отсортировать так, чтобы элементы соответствовали порядку в спецификации.
Может такое уже решалось и я просто не могу найти?

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Привет!

Получить элементы - просто, использовать FilteredElementCollector, во второй параметр передать Id спецификации. Тут проблемка только в том, что там будут RevitLinkInstance (в случае, если стоит галка подбора элементов из связанного файла).

С сортировкой, фильтрацией и группировкой по полям с формулами, к сожалению, на данный момент никак. Сначала думал, что можно хотя бы формулы полей спецификации получить, тогда хотя бы можно было бы самим парсить формулу и значения рассчитывать, но нет, никак. dotPeek-ом тоже пытался изучать, ну как там какие protected/private поля/методы, но тоже нет :-(

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Александр Игнатович, а вот и можно, но с ограничением ;)

Я не стал вчера сам отвечать - ждал ответов от других. Вдруг есть что-то, чего я не знаю))
Итак, лайфхак такой:
1. Получаем все элементы на виде спецификации
2. В параметр "Комментарий" через разделитель добавляем Id элемента. Можно и без разделителя, кстати - просто переписать комментарий, так как будет откат
3. В спецификацию добавляем поле с параметром "Комментарий", если его там нет
4. Через TableData читаем спецификацию в том виде, в котором мы ее видим на экране. Ищем комментарий и парсим оттуда Id элемента
5. Откатываем транзакцию
6. Профит!

В этом случае мне вообще пофиг какие там фильтры настроены, какие сортировки и т.д. Единственная и главная проблема (почему я и ждал ответа) - этот код бесполезен, если в настройках спецификации снята галочка "Для каждого экземпляра". Это вот меня конечно расстроило - вместо гибкости плагина, пришлось вводить ограничения

Ну и сама магия:
Код - C# [Выбрать]
  1. private static List<Element> GetSortedElementsFromSchedule(ViewSchedule viewSchedule, List<Element> elements)
  2. {
  3.     List<Element> sortedElements = new List<Element>();
  4.  
  5.     using (SubTransaction transaction = new SubTransaction(viewSchedule.Document))
  6.     {
  7.         transaction.Start();
  8.  
  9.         // Разделитель
  10.         var separator = "$ElementId=";
  11.  
  12.         // Записываем Id всех элементов в параметр "Комментарий"
  13.         elements.ForEach(e =>
  14.         {
  15.             var parameter = e.get_Parameter(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS);
  16.             parameter.Set(parameter.AsString() + separator + e.Id.IntegerValue);
  17.         });
  18.  
  19.         // К спецификации добавляем поле. Код из справки, за исключением try {} catch{}
  20.         IList<SchedulableField> schedulableFields = viewSchedule.Definition.GetSchedulableFields();
  21.  
  22.         foreach (SchedulableField sf in schedulableFields)
  23.         {
  24.             if (sf.FieldType != ScheduleFieldType.Instance)
  25.                 continue;
  26.             if (sf.ParameterId.IntegerValue != (int)BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS)
  27.                 continue;
  28.  
  29.             bool fieldAlreadyAdded = false;
  30.             //Get all schedule field ids
  31.             IList<ScheduleFieldId> ids = viewSchedule.Definition.GetFieldOrder();
  32.             foreach (ScheduleFieldId id in ids)
  33.             {
  34.                 try
  35.                 {
  36.                     if (viewSchedule.Definition.GetField(id).GetSchedulableField() == sf)
  37.                     {
  38.                         fieldAlreadyAdded = true;
  39.                         break;
  40.                     }
  41.                 }
  42.                 catch
  43.                 {
  44.                     // Тут бывают какие-то ошибки, но мне они не важны, поэтому проще их "проглатить"
  45.                 }
  46.             }
  47.  
  48.             if (fieldAlreadyAdded == false)
  49.             {
  50.                 viewSchedule.Definition.AddField(sf);
  51.             }
  52.         }
  53.  
  54.         // Ну и сама магия - просто читаем получившуюся спецификацию по ячейкам и получаем
  55.         // элементы уже в том порядке, в котором мы их видим в спецификации
  56.         TableSectionData sectionData = viewSchedule.GetTableData().GetSectionData(SectionType.Body);
  57.         for (int r = sectionData.FirstRowNumber; r <= sectionData.LastRowNumber; r++)
  58.         {
  59.             for (int c = sectionData.FirstColumnNumber; c <= sectionData.LastColumnNumber; c++)
  60.             {
  61.                 var cellValue = viewSchedule.GetCellText(SectionType.Body, r, c);
  62.                 if (cellValue.Contains(separator))
  63.                 {
  64.                     var idStr = cellValue.Split(separator.ToCharArray()).Last();
  65.                     if (!string.IsNullOrEmpty(idStr))
  66.                     {
  67.                         // Делаем устойчивым к ошибкам - при наличии ошибок все равно код завершится,
  68.                         // а я буду знать о возможных проблемах. На мой взгляд лучше, чем полное прерывание метода
  69.                         try
  70.                         {
  71.                             sortedElements.Add(viewSchedule.Document.GetElement(new ElementId(Convert.ToInt32(idStr))));
  72.                         }
  73.                         catch (Exception exception)
  74.                         {
  75.                             ExceptionBox.Show(exception);
  76.                         }
  77.                     }
  78.                 }
  79.             }
  80.         }
  81.  
  82.         // Откатываем транзакцию
  83.         transaction.RollBack();
  84.     }
  85.  
  86.     return sortedElements;
  87. }

Оффлайн Александр Игнатович

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Ну как минимум, теряется группировка, как максимум - "комментарий" может использоваться в сортировках/группировках или фильтрах, лучше уж создать свой параметр.

Да и, кстати, после записи в параметр и добавления поля в спецификацию регенерацию не забыли?

Ну и есть ещё один не охваченный момент: элементы из связанных файлов.

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Ну как минимум, теряется группировка
Про это я и написал
как максимум - "комментарий" может использоваться в сортировках/группировках или фильтрах, лучше уж создать свой параметр
Пока оставлю так. Создавать свой параметр долго и муторно. Плагин этого "не достоин" =)
Да и, кстати, после записи в параметр и добавления поля в спецификацию регенерацию не забыли?
Сколько вот тестировал - не нужна была
Ну и есть ещё один не охваченный момент: элементы из связанных файлов
Они мне, по идее, и не важны/не нужны до того момента, пока пользователи не убедят меня в обратном. Что вряд-ли произойдет