ADN Open CIS
Сообщество программистов Autodesk в СНГ

30/12/2013

API для работы с семействами. Типоразмеры вложенного семейства, поиск типоразмеров и экземпляров семейства

Приветствую вас в третьей, заключительно части серии статей посвященных API для работы с семействами в проекте.

В последней части мы рассмотрим следующие темы:

  • Поиск определенных типоразмеров в проекте
  • Поиск определенных экземпляров конкретного семейства
  • Отображение типоразмеров семейства Дверь
  • Изменение типоразмера вложенного семейства.

Основная функциональность работы с семействами была представлена Стивеном Кэмпбелом (Steven Campbell) в его докладе Ключевые концепции при работе с семействами на Revit DevCamp в Москве. Предыдущие статьи вы можете прочитать по следующим ссылкам: первая часть, вторая часть.

В предыдущей статье мы обсудили как программно обработать выбор семейства или любого другого элемента в интерфейсе Revit. Но что если вам нужно автоматом выбрать и изменить все экземпляры определенного типоразмера?

Время идет, семейства, с которыми нам необходимо работать, становятся все сложнее. Сегодня мы будем работать с кухонными шкафами, в которых есть вложенные семейства, которые представляют собой различные варианты панелей дверей шкафов.

В этом примере мы будем менять тип двери, т.е. будем изменять типоразмер вложенного семейства.

 

Последняя команды в нашей серии статей по API семейств называется CmdKitchenUpdate. Ее необходимо запустить в модели, представляющей собой дизайн кухни. В ней определяются все возможные типы панелей дверей для шкафов, автоматически выбираются все кухонные шкафы, отображается текущий тип панели, предлагается выбрать новый и применяется выбранный тип для всех шкафов.

Поиск определенных типоразмеров

Первым делом нам необходимо найти все возможные типоразмеры дверей шкафов.

Как всегда, воспользуемся для этих целей классом FilteredElementCollector. В нашем случае нам нужно выбрать все типоразмеры (класс FamilySymbol) категории Обобщенные модели. Для того чтобы определить какие из них являются панелями дверей шкафов, мы воспользуемся LINQ и выберем только те элементы, название которых начинается с «Door panel - » (Панель двери). Код выглядит вот так:

Код - C#: [Выделить]
  1.   // Выбор всех панелей дверей шкафов.
  2.   List<Element> door_panel_types = new List<Element>(
  3.     new FilteredElementCollector( doc )
  4.       .OfCategory( BuiltInCategory.OST_GenericModel )
  5.       .OfClass( typeof( FamilySymbol ) )
  6.       .Where<Element>( e => e.Name.StartsWith(
  7.         "Door panel - " ) ) );

Поиск экземпляров семейств

Так как нам нужно изменить панели дверей для всей кухни, то нам нужно сначала выбрать все кухонные шкафы, которые есть в проекте.

В очередной раз воспользуется Filtered ElementCollector. Для фильтрации всех экземпляров шкафов нам нужно применить два «быстрых» фильтра.

Можно конечно применить и большее количество фильтров, и я обязательно это сделаю, если буду работать с большой моделью. Пока же для примера ограничимся двумя.

В качестве последней проверки я удостоверюсь, что у элемента действительно существует параметр «Тип панели двери», который я хочу изменить.

В большой и сложной модели, для достижения оптимальной производительности, такою проверку необходимо сделать с помощью фильтрации по параметру. В нашем тестовом примере я воспользуюсь LINQ.

Код - C#: [Выделить]
  1.   // Поиск всех кухонных шкафов
  2.   // у которых есть параметр Door Panel Type  («Тип панели двери»)
  3.   IEnumerable<Element> casework
  4.     = new FilteredElementCollector( doc )
  5.       .OfCategory( BuiltInCategory.OST_Casework ) // Шкафы
  6.       .OfClass( typeof( FamilyInstance ) )
  7.       .Where<Element>( e =>
  8.         (null != e.get_Parameter(
  9.           " Door Panel Type" )) );

Отображение доступных панелей

Поиск всех возможных типов панелей и выбор всех шкафов в проекте по сути является главной задачей команды.

Остались достаточно простые шаги:

  • Отобразить пользователю текущий тип панели, или «НЕСКОЛЬКО», если среди выбранных шкафов используются различные типы панелей дверей.
  • Отобразить список доступных типов панелей дверей и предложить пользователю выбрать один из них.
  • Применить выбранный тип для всех шкафов.

Для решения первых двух задач мы воспользуемся обычной формой .NET.

 

Форма содержит список всех типов панелей дверей, которые мы передали в конструктор формы, и отображает эти типы пользователю в раскрывающемся списке. Также отображается текущий тип панели.

Получить выбранный тип дверей достаточно просто:

Код - C#: [Выделить]
  1.   public DoorPanelTypeSelectorForm(
  2.     string current_door_panel_type_name,
  3.     IEnumerable<Element> door_panel_types )
  4.   {
  5.     InitializeComponent();
  6.     label2.Text = current_door_panel_type_name;
  7.     comboBox1.DataSource = door_panel_types;
  8.     comboBox1.DisplayMember = "Name"; // Свойство класса Element, значение которого необходимо отображать в списке.
  9.     comboBox1.SelectedIndex = 0;
  10.   }
  11.  
  12.   public Element SelectedItem
  13.   {
  14.     get
  15.     {
  16.       return comboBox1.SelectedItem as Element;
  17.     }
  18.   }

Изменение типоразмера вложенного семейства

После того как мы показали форму выбора пользователю и пользователь выбрал требуемый тип панели, применение выбранного типа к шкафам достигается очень просто. Нужно всего лишь задать значение параметра Тип панели двери для всех выбранных шкафов. Очевидно, что изменение параметра необходимо делать в рамках транзакции.

Код - C#: [Выделить]
  1.   // Отображение формы для выбора типа панели дверей
  2.   DoorPanelTypeSelectorForm form
  3.     = new DoorPanelTypeSelectorForm(
  4.       current_door_panel_type_name,
  5.       door_panel_types );
  6.  
  7.   if( System.Windows.Forms.DialogResult.OK
  8.     == form.ShowDialog() )
  9.   {
  10.     FamilySymbol door_panel_type
  11.       = form.SelectedItem as FamilySymbol;
  12.  
  13.     ElementId id = door_panel_type.Id;
  14.  
  15.     using( Transaction tx = new Transaction( doc ) )
  16.     {
  17.       tx.Start( "Изменение типа панели" );
  18.  
  19.       foreach( Element e in casework )
  20.       {
  21.         Parameter p = e.get_Parameter(
  22.           "Door Panel Type" ); // Тип панели двери
  23.  
  24.         p.Set( id );
  25.       }
  26.       tx.Commit();
  27.     }
  28.   }

Внешнее приложение

Реализация класса реализующего интерфейс IExternalApplication очень проста.

Так как нам в конечном итоге нужно отобразить три команды, мы можем использовать StackedPanel для отображения трех команд на ленте.

 

Вот полный код класса:

Код - C#: [Выделить]
  1. class App : IExternalApplication
  2. {
  3.   /// <summary>
  4.   /// Добавление трех команд
  5.   /// на панель ленты
  6.   /// </summary>
  7.   void PopulatePanel( RibbonPanel p )
  8.   {
  9.     string path = Assembly.GetExecutingAssembly()
  10.       .Location;
  11.  
  12.     RibbonItemData i1 = new PushButtonData(
  13.         "TableLoadPlace", "1 Загрузка и размещение стола",
  14.         path, "FamilyApi.CmdTableLoadPlace" );
  15.  
  16.     i1.ToolTip = "Загрузка семейства Стол и размещение экземпляра семейства в проекте";
  17.  
  18.     RibbonItemData i2 = new PushButtonData(
  19.       "TableModify", "2 Новый типоразмер стола",
  20.       path, "FamilyApi.CmdTableNewTypeModify" );
  21.  
  22.     i2.ToolTip = "Создание нового типоразмера стола и применение нового типоразмера к экземпляру";
  23.  
  24.     RibbonItemData i3 = new PushButtonData(
  25.       "KitchenUpdate", "3 Обновление кухни",
  26.       path, "FamilyApi.CmdKitchenUpdate" );
  27.  
  28.     i3.ToolTip = "Выбор и изменение всех кухонных шкафов.";
  29.  
  30.     p.AddStackedItems( i1, i2, i3 );
  31.   }
  32.  
  33.   public Result OnStartup(
  34.     UIControlledApplication a )
  35.   {
  36.     PopulatePanel(
  37.       a.CreateRibbonPanel(
  38.         Util.Caption ) );
  39.  
  40.     return Result.Succeeded;
  41.   }
  42.  
  43.   public Result OnShutdown(
  44.     UIControlledApplication a )
  45.   {
  46.     return Result.Succeeded;
  47.   }
  48. }

Заключение

Я думаю в наконец то закрыл все вопросы связанные с использованием API для работы с семействами.

Я очень счастлив, что у меня получилась довольно простая реализация всех команд.

Ну и наконец, я хотел бы выложить архив с полным исходным кодом для Visual Studio всех команд, которые мы обсуждали в нашей серии статей, а также семейство Стол и модель кухни.

Источник: http://thebuildingcoder.typepad.com/blog/2013/07/family-api-nested-type-instance-and-symbol-retrieval.html

Обсуждение: http://adn-cis.org/forum/index.php?topic=426

Опубликовано 30.12.2013
Отредактировано 30.12.2013 в 09:22:28