Использование типизированных коллекций в фильтрах и формах
В сегодняшней теме обсудим использование типизированных коллекций для легкой и эффективной работы со списками элементов Revit в Windows Forms, а именно:
- Извлечение всех печатных видов плана этажей из модели с помощью всего одной строчки кода
- Извлечение всех выбранных видов плана этажей из списка на форме с помощью одной строки кода
Это первый шаг к подготовки реализации новой возможности редактирования помещения для моего упрощенного 2D BIM редактора.
Приблизительный план для выгрузки данных из базы данных Revit выглядит так:
- Запустить команду RoomAppEditor для экспорта планов этажей
- Отобразить список всех планов этажей на форме
- Выбрать виды, которые нужно экспортировать и нажать ОК.
- Отобразить категории на форме
- Выбрать категории и нажать ОК.
- Сохранить соответствующую графическую и другую информацию в облачной базе данных.
Следующие шаги по редактированию и скачиванию информации останутся такими же, что и в первоначальной реализации:
- Отобразить модель на мобильном устройстве.
- Отредактировать информацию, как графическую, так и нет.
- Обновить модель в Revit в реальном времени.
Сегодня рассмотрим первые 3 шага.
Недавно я упоминал об интересном и полезном типизированном методе ToDictionary() для конвертации FilteredElementCollector в Dictionary.
Сегодня же я бы хотел рассмотреть подобные примеры, такие как заполнение списка на форме и выбор результата выделенных пользователем позиций в типизированный список.
Я реализовал новую команду CmdUploadViews.
Команда вызывает форму для выбора планов этажей, которые необходимо экспортировать. Форма называется FrmSelectViews.
Давайте первым делом взглянем на нее.
FrmSelectViews
С помощью этой формы пользователь может выбрать планы этажей.
Ниже представлен скриншот с планами этажей в диспетчере проекта Revit для простой модели.
С помощью Revit Lookup посмотрим, как объекты класса ViewPlan хранятся в базе данных Revit. Можно заметить, что нас интересуют не все из них:
Некоторые из этих видов являются планами потолков, а не этажей. Некоторые из видов вообще не понятны.
Мы можем отфильтровать необходимые нам виды по свойствам ViewType и CanBePrinted.
Сделаем фильтрацию с помощью метода LINQ Where, добавив его в FilteredElementCollector.
Заметьте, что класс FilteredElementCollector сам является перечислением, поэтому мы можем совмещать его с другими типизированными фильтрами для постобработки результатов фильтрации.
Следующий код выполняет всю фильтрацию и генерирует типизированный список видов типа План Этажа, который мы можем использовать для заполнения списка на форме при помощи свойств DataSource иDisplayMember.
- List<ViewPlan> views = new List<ViewPlan>(
- new FilteredElementCollector( _doc )
- .OfClass( typeof( ViewPlan ) )
- .Cast<ViewPlan>()
- .Where<ViewPlan>( v => v.CanBePrinted
- && ViewType.FloorPlan == v.ViewType ) );
Похожим образом можно получить список выбранных пользователем видов. Для этого необходимо преобразовать все объекты CheckedItems к ViewPlan и затем сконвертировать их в типизированный список с помощью LINQ.
Ниже представлен полный код формы:
- /// <summary>
- /// Выбор планов этажей.
- /// </summary>
- public partial class FrmSelectViews : Form
- {
- /// <summary>
- /// Проект REvit
- /// </summary>
- Document _doc;
- /// <summary>
- /// Передаем ссылку на документ
- /// </summary>
- /// <param name="doc"></param>
- public FrmSelectViews( Document doc )
- {
- InitializeComponent();
- _doc = doc;
- }
- /// <summary>
- /// Извлекаем планы этажей из проекта.
- /// </summary>
- private void FrmSelectViews_Load(
- object sender,
- EventArgs e )
- {
- List<ViewPlan> views = new List<ViewPlan>(
- new FilteredElementCollector( _doc )
- .OfClass( typeof( ViewPlan ) )
- .Cast<ViewPlan>()
- .Where<ViewPlan>( v => v.CanBePrinted
- && ViewType.FloorPlan == v.ViewType ) );
- checkedListBox1.DataSource = views;
- checkedListBox1.DisplayMember = "Name";
- }
- /// <summary>
- /// Выбираем отмеченные планы этажей
- /// </summary>
- /// <returns></returns>
- public List<ViewPlan> GetSelectedViews()
- {
- return checkedListBox1.CheckedItems
- .Cast<ViewPlan>().ToList<ViewPlan>();
- }
- }
CmdUploadViews
Сама команда по сути не делает ничего за исключением вызова формы с отображением списка планов этажей.
Две важные детали:
- В команде определяем главное окно Revit и в дальнейшем используем его как родительское окно для нашей формы. Это необходимо для корректной обработки минимизации окна Revit и восстановления его в исходное состояние.
- Еще раз напомню, что используются типизированные коллекции для того чтобы не перебирать каждый элемент. Для отображения сообщения используется методы Srting.Join при создании списка выбранных видов.
Код команды:
- public Result Execute(
- ExternalCommandData commandData,
- ref string message,
- ElementSet elements )
- {
- IWin32Window revit_window
- = new JtWindowHandle(
- ComponentManager.ApplicationWindow );
- UIApplication uiapp = commandData.Application;
- UIDocument uidoc = uiapp.ActiveUIDocument;
- Application app = uiapp.Application;
- Document doc = uidoc.Document;
- if( null == doc )
- {
- Util.ErrorMsg( "Запустите команды в "
- + " открытом проекте" );
- return Result.Failed;
- }
- FrmSelectViews form = new FrmSelectViews( doc );
- if( DialogResult.OK == form.ShowDialog(
- revit_window ) )
- {
- List<ViewPlan> views = form.GetSelectedViews();
- int n = views.Count;
- string caption = string.Format(
- "{0} Планов этажей выбрано",
- n );
- string list = string.Join( ", ",
- views.Select<Element, string>(
- e => e.Name ) );
- TaskDialog.Show( caption, list );
- //List<Category> categories = new List<Category>();
- }
- return Result.Succeeded;
- }
- }
Форма со списком планов этажей выглядит так:
Диалог с результатами выбора видов:
Скачать проект можно как всегда на GitHub.
Надеюсь данная статья поможет вам в использовании типизированных коллекций в Revit API, вместо перебора всех элементов.
Следующие шагни рассмотрим чуть позднее.
Обсуждение: http://adn-cis.org/forum/index.php?topic=645
Опубликовано 31.03.2014