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

31/03/2014

Использование типизированных коллекций в фильтрах и формах

В сегодняшней теме обсудим использование типизированных коллекций для легкой и эффективной работы со списками элементов Revit в Windows Forms, а именно:

  • Извлечение всех печатных видов плана этажей из модели с помощью всего одной строчки кода
  • Извлечение всех выбранных видов плана этажей из списка на форме с помощью одной строки кода

Это первый шаг к подготовки реализации новой возможности редактирования помещения для моего упрощенного 2D BIM редактора.

Приблизительный план для выгрузки данных из базы данных Revit выглядит так:

  1. Запустить команду RoomAppEditor для экспорта планов этажей
  2. Отобразить список всех планов этажей на форме
  3. Выбрать виды, которые нужно экспортировать и нажать ОК.
  4. Отобразить категории на форме
  5. Выбрать категории и нажать ОК.
  6. Сохранить соответствующую графическую и другую информацию в облачной базе данных.

Следующие шаги по редактированию и скачиванию информации останутся такими же, что и в первоначальной реализации:

  1. Отобразить модель на мобильном устройстве.
  2. Отредактировать информацию, как графическую, так и нет.
  3. Обновить модель в Revit в реальном времени.

Сегодня рассмотрим первые 3 шага.

Недавно я упоминал об интересном и полезном типизированном методе ToDictionary() для конвертации FilteredElementCollector в Dictionary.

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

Я реализовал новую команду CmdUploadViews.

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

Давайте первым делом взглянем на нее.

FrmSelectViews

С помощью этой формы пользователь может выбрать планы этажей.

Ниже представлен скриншот с планами этажей в диспетчере проекта Revit для простой модели.

 

С помощью Revit Lookup посмотрим, как объекты класса ViewPlan хранятся в базе данных Revit. Можно заметить, что нас интересуют не все из них:

 

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

Мы можем отфильтровать необходимые нам виды по свойствам ViewType и CanBePrinted.

Сделаем фильтрацию с помощью метода LINQ Where, добавив его в FilteredElementCollector.

Заметьте, что класс FilteredElementCollector сам является перечислением, поэтому мы можем совмещать его с другими типизированными фильтрами для постобработки результатов фильтрации.

Следующий код выполняет всю фильтрацию и генерирует типизированный список видов типа План Этажа, который мы можем использовать для заполнения списка на форме при помощи свойств DataSource иDisplayMember.

Код - C#: [Выделить]
  1.   List<ViewPlan> views = new List<ViewPlan>(
  2.     new FilteredElementCollector( _doc )
  3.       .OfClass( typeof( ViewPlan ) )
  4.       .Cast<ViewPlan>()
  5.       .Where<ViewPlan>( v => v.CanBePrinted
  6.         && ViewType.FloorPlan == v.ViewType ) );

Похожим образом можно получить список выбранных пользователем видов. Для этого необходимо преобразовать все объекты CheckedItems к ViewPlan и затем сконвертировать их в типизированный список с помощью LINQ.

Ниже представлен полный код формы:

Код - C#: [Выделить]
  1.   /// <summary>
  2.   /// Выбор планов этажей.
  3.   /// </summary>
  4.   public partial class FrmSelectViews : Form
  5.   {
  6.     /// <summary>
  7.     /// Проект REvit
  8.     /// </summary>
  9.     Document _doc;
  10.  
  11.     /// <summary>
  12.     /// Передаем ссылку на документ
  13.     /// </summary>
  14.     /// <param name="doc"></param>
  15.     public FrmSelectViews( Document doc )
  16.     {
  17.       InitializeComponent();
  18.  
  19.       _doc = doc;
  20.     }
  21.  
  22.     /// <summary>
  23.     /// Извлекаем планы этажей из проекта.
  24.     /// </summary>
  25.     private void FrmSelectViews_Load(
  26.       object sender,
  27.       EventArgs e )
  28.     {
  29.       List<ViewPlan> views = new List<ViewPlan>(
  30.         new FilteredElementCollector( _doc )
  31.           .OfClass( typeof( ViewPlan ) )
  32.           .Cast<ViewPlan>()
  33.           .Where<ViewPlan>( v => v.CanBePrinted
  34.             && ViewType.FloorPlan == v.ViewType ) );
  35.  
  36.       checkedListBox1.DataSource = views;
  37.       checkedListBox1.DisplayMember = "Name";
  38.     }
  39.  
  40.     /// <summary>
  41.     /// Выбираем отмеченные планы этажей
  42.     /// </summary>
  43.     /// <returns></returns>
  44.     public List<ViewPlan> GetSelectedViews()
  45.     {
  46.       return checkedListBox1.CheckedItems
  47.         .Cast<ViewPlan>().ToList<ViewPlan>();
  48.     }
  49.   }

CmdUploadViews

Сама команда по сути не делает ничего за исключением вызова формы с отображением списка планов этажей.

Две важные детали:

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

Код команды:

Код - C#: [Выделить]
  1.     public Result Execute(
  2.       ExternalCommandData commandData,
  3.       ref string message,
  4.       ElementSet elements )
  5.     {
  6.       IWin32Window revit_window
  7.         = new JtWindowHandle(
  8.           ComponentManager.ApplicationWindow );
  9.  
  10.       UIApplication uiapp = commandData.Application;
  11.       UIDocument uidoc = uiapp.ActiveUIDocument;
  12.       Application app = uiapp.Application;
  13.       Document doc = uidoc.Document;
  14.  
  15.       if( null == doc )
  16.       {
  17.         Util.ErrorMsg( "Запустите команды в "
  18.           + " открытом проекте" );
  19.         return Result.Failed;
  20.       }
  21.  
  22.       FrmSelectViews form = new FrmSelectViews( doc );
  23.  
  24.       if( DialogResult.OK == form.ShowDialog(
  25.         revit_window ) )
  26.       {
  27.         List<ViewPlan> views = form.GetSelectedViews();
  28.  
  29.         int n = views.Count;
  30.  
  31.         string caption = string.Format(
  32.           "{0} Планов этажей выбрано",
  33.           n );
  34.  
  35.         string list = string.Join( ", ",
  36.           views.Select<Element, string>(
  37.             e => e.Name ) );
  38.  
  39.         TaskDialog.Show( caption, list );
  40.  
  41.         //List<Category> categories = new List<Category>();
  42.       }
  43.       return Result.Succeeded;
  44.     }
  45.   }

Форма со списком планов этажей выглядит так:

 

Диалог с результатами выбора видов:

 

Скачать проект можно как всегда на GitHub.

Надеюсь данная статья поможет вам в использовании типизированных коллекций в Revit API, вместо перебора всех элементов.

Следующие шагни рассмотрим чуть позднее.

Источник: http://thebuildingcoder.typepad.com/blog/2014/03/using-generic-collections-with-filters-and-forms.html

 

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

Опубликовано 31.03.2014