Создание пользовательской закрепляемой панели

Автор Тема: Создание пользовательской закрепляемой панели  (Прочитано 2340 раз)

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

Оффлайн Александр РивилисАвтор темы

  • Administrator
  • *****
  • Сообщений: 6890
  • Карма: 769
  • Рыцарь ObjectARX
  • Skype: rivilis
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн shss

  • ADN Club
  • ***
  • Сообщений: 173
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Добрый день!
Спасибо за статью.
Возник вопрос, а как обращаться к элементам активного документа Revit из закрепляемой панели?
то есть передать в MyControl Document?

Спасибо

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
shss, добрый день.
Точно также, как и из немодальной формы - с помощью обработки события OnIdling. Напрямую никак. Вернее возможно передать в закрепляемую панель активный документ при помощи обработки события ViewActivated, как это описано в статье, но его ни в коем случае нельзя использовать для обращения в элементам документа. Revit почти гарантировано "упадет". Этот способ можно использовать только для заполнения некоторых данных из активного документа при переключении вида.

Оффлайн shss

  • ADN Club
  • ***
  • Сообщений: 173
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Виктор, спасибо за подсказку!
Буду искать в этом направлении.
Ну а в целом, конечно, непонятно назначение данной панели, с одной стороны она как бы "нативная", но обращаться с ней нужно, как с немодальной (некой внешней) формой.
Опять же отслеживать все изменения модели пока "висит" форма, получается невозможно, если не будет кнопочки а ля "Обновить данные" (на примере списка элементов).

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
Нативная то она нативная, тем не менее, как ни крути, она пользовательская и в то же время она не блокирует пользовательский интерфейс, т.е. по сути это и есть немодальная форма, но тесно встроена в интерфейс.
Кнопочку "обновить данные" конечно можно сделать. Другой вопрос на сколько это легко или трудно.
Думаю я напишу статью в ближайшее время как работать с немодальными формами.

По поводу назначения панели. Как пример, в Revit есть встроенный диспетчер проектов с каталогом семейств. Представьте себе собственный каталог онлайн-семейств, когда мы ищем некое семейство в каталоге и загружаем его прямо в проект из интернета, не выполняя никаких лишний действий. При этом каталог можно встроить прямо в интерфейс самого Revit в виде закрепляемой панели. По моему здорово.
Другой пример. Элемент в модели связан с некой сущностью во внешней базе данных. При выделении элемента можно отображать свойства этой сущности из базы данных. Закрепляемая панель как раз подходит для таких случаев.
Т.е. эта возможность безусловна полезна. Но это не значит что ее нужно применять везде подряд.

Оффлайн shss

  • ADN Club
  • ***
  • Сообщений: 173
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Да тут я с Вами, совершенно согласен.
Но все же это странно, что нет доступа даже к БД модели, просто проводя аналогию с Navisworks или AuoCAD из DockablePanel я всегда имею доступ к элементам активной модели.
Статьи про немодальные формы было бы очень интересно почитать.

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
shss, про AutoCAD я не подскажу, так как практически не работал с ним. В Navisworks же на сколько мне известно (могу ошибаться), мы можем только читать данные.
Позиция Autodesk по поводу того, почему нельзя откуда попало вызывать методы Revit API своидтся к тому, что в момент когда что-то вы делает с моделью, этот же самый элемент может быть изменен самим Revit'ом или другим приложением и в итоге внутренняя база Revit может поломаться. Возможно все дело в структуре хранения данных и внетренней работы Revit. Как программист, я понимаю, что все это решаемо в теории. На практике может это потребует неимоверхных услиий, вплоть до пееписывания кода с нуля, для того чтобы была возможность вызывать методы Revit API отовсюду. Поэтому придется мириться с тем что есть и находить обходные пути, для того чтобы реализовать ту или иную задачу.
Правда я еще могу понять, почему запрещено изменению модели из другого потока или из любого места кода, но вот почему запрещено даже чтению - я не знаю. Причем если в 2014 версии и ниже еще можно было обращаться к элементам из другого потока именно для чтения данных (хотя и крайне не рекомендовано), то в 2015 Revit падает с ошибкой.

Оффлайн shss

  • ADN Club
  • ***
  • Сообщений: 173
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Спасибо за развернутый ответ.
Все же, видимо, придется использовать диалоговое окно, хотя, как ни старался, пытался уйти от него.

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
А что у вас за задача?
С диалоговыми окнами несомненно проще, но как я сказал, возможно ведь и в закрепляемой панели. Просто придется немного повозиться:)

Оффлайн shss

  • ADN Club
  • ***
  • Сообщений: 173
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Задача очень простая: используя параметры элементов (высота, длина, объем и т.д.) создавать View Filter и применять его.
То есть для отображения параметров элементов мне надо перебрать их в модели и вывести пользователю, после его выбора создать фильтр и применить его к модели.
Каждый раз открывать диалоговое окно не совсем удобно, причем после применения модель надо повертеть, и если, что-то не нравится изменить фильтр. Прыгать туда-сюда пользователю не удобно.
Поэтому и хотел вынести в закрепляемой панели.

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
Вполне логично поместить это в закрепляемую панель.

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

Собственно не так уж и сложно :)

Вот пример кода для модальной формы. Для закрепляемой панели будет похожий код:
Код - C# [Выбрать]
  1.     public partial class Form1 : Form
  2.     {
  3.         private readonly UIControlledApplication _uiControlledApplication;
  4.  
  5.         /// <summary>
  6.         /// В конструктор формы передаем объект типа UIControlledApplication
  7.         /// для дальнейшей подписки на событие OnIdling
  8.         /// </summary>
  9.         /// <param name="uiControlledApplication"></param>
  10.         public Form1(UIControlledApplication uiControlledApplication)
  11.         {
  12.             _uiControlledApplication = uiControlledApplication;            
  13.             InitializeComponent();
  14.         }
  15.  
  16.         private void button1_Click(object sender, EventArgs e)
  17.         {
  18.             // При нажатии на кнопку, подписываемся на событие
  19.            _uiControlledApplication.Idling += _uiControlledApplication_Idling;
  20.            
  21.         }
  22.  
  23.         void _uiControlledApplication_Idling(object sender, Autodesk.Revit.UI.Events.IdlingEventArgs e)
  24.         {
  25.             // Получаем объект типа UIApplication
  26.             var uapp = (UIApplication)(sender);
  27.  
  28.             // и из него получаем активный документ
  29.             var doc = uapp.ActiveUIDocument.Document;
  30.  
  31.             // делаем то что хотим с активным документом
  32.             MessageBox.Show(doc.Title);
  33.  
  34.             // и не забываем отписываться от события.
  35.             _uiControlledApplication.Idling -= _uiControlledApplication_Idling;
  36.         }
  37.     }

И напоследок исходный код демо приложения как обращаться к активному документу из модальной формы. (во волжении)
« Последнее редактирование: 19-08-2014, 16:56:14 от Виктор Чекалин »

Оффлайн shss

  • ADN Club
  • ***
  • Сообщений: 173
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Спасибо за подсказку, Виктор!
я вот тут тоже такое расковырял
http://thebuildingcoder.typepad.com/blog/2009/02/revit-window-handle-and-modeless-dialogues.html
но у меня возник вопрос
в варианте с формой, мы передаем форме:
Код - C# [Выбрать]
  1.  App.Form.Show(new Win32Window(ComponentManager.ApplicationWindow));
а в варианте с панелью не получается передать:
Код - C# [Выбрать]
  1. DockablePaneId dpid = new DockablePaneId(new Guid("E6EF9DE9-F5F2-454B-8968-4BA2622E5CE6"));
  2.                 if (dpid != null) {
  3.                     DockablePane dp = commandData.Application.GetDockablePane(dpid);
  4.                 dp.Show();
Поправьте меня если я не прав.

P.S. тут не совсем все так просто, как может показаться на первый взгляд :)
« Последнее редактирование: 19-08-2014, 18:57:59 от Виктор Чекалин »

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
В случае панели это и не нужно.  В варианте с немодальной формой я передаю идентификатор родительского окна, тем самым указываю форме, что окно Revit является главноым для немодальнйо формы. Это необязательно и необходимо для того, чтобы немодальная форма, например, сворачивалась при сворачивании Revit и при активации окна Revit, форма также появлялась на переднем плане. Можете поэксперементировать с поведенем формы, с передачей параметра new Win32Window(ComponentManager.ApplicationWindow) и без него, чтобы понять разницу.

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

Оффлайн shss

  • ADN Club
  • ***
  • Сообщений: 173
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Все  разобрался, Виктор, огромное спасибо за помощь!

Оффлайн SatanaXIII

  • ADN OPEN
  • Сообщений: 13
  • Карма: 0
Здравствуйте. Не могу организовать работу с Revit из закрепляемой панели (WPF).
Пробовал посредством обращения через сохраненный Application, и через внешние события, и через событие простоя.
Получается считывать названия документов и кое чего по мелочи.
Не могу получить доступ к чертежу (PickObjects, например) или изменить что-либо на чертеже.
Из WindowsForms-окна все работает замечательно. Но, применяя неважно какой подход, любое обращение к чертежу из WPF-панели заканчивается выбросом исключения:
Цитировать
{Autodesk.Revit.Exceptions.InvalidOperationException: The active view is non-graphical and does not support capture of the focus for pick operations.
При чем активный вид на самом деле-то правильный и все с ним хорошо.
Как получить доступ к элементам чертежа из WPF-панели?
P.S. Revit 2016.

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
SatanaXIII, а как вы в итоге вызываете методы из закрепляемой панели?
Стоит отметить, что работа с Revit API возможна только в "правильных" контекстах. Вы не можете вызывать методы Revit API откуда попало. Случай с закрепляемой панелью похож на работу с немодальным окном.

Есть небольшая статья по этому поводу.

Оффлайн SatanaXIII

  • ADN OPEN
  • Сообщений: 13
  • Карма: 0
Есть небольшая статья по этому поводу.
Статью читал. В ней сказано, что через событие Idling все же можно добраться до модели ревита.
Стоит отметить, что работа с Revit API возможна только в "правильных" контекстах. Вы не можете вызывать методы Revit API откуда попало. Случай с закрепляемой панелью похож на работу с немодальным окном.
Опять же некоторые методы можно вызывать откуда попало, некоторые нельзя (см. пример). Эта неточность вносит некоторый сумбур.

SatanaXIII, а как вы в итоге вызываете методы из закрепляемой панели?
Приведу пример:
Извините, вам запрещён просмотр содержимого спойлеров.

Таким образом получить список выбранных элементов (GetElementIds) можно, а вот выбрать (PickElementsByRectangle) нет.

Оффлайн Виктор Чекалин

  • Administrator
  • *****
  • Сообщений: 669
  • Карма: 90
  • Skype: chekalin-v
SatanaXIII,
Когда вызывается метод EventSelect.Raise(); - вот тут то как раз и происходит выполнение метода RevitAPI в неправильном контексте. Последствия могут быть, а могут и не быть.
Вообще изначальная ошибка говорит о том, что вид не подходящий для выбора объектов.
Если вы обработке события Idling отобразить текущий вид, что там будет?
Код - C# [Выбрать]
  1. var currentView = uapp.ActiveUIDocument.ActiveView;
Интересует тип вида и название.

Оффлайн SatanaXIII

  • ADN OPEN
  • Сообщений: 13
  • Карма: 0
Когда вызывается метод EventSelect.Raise(); - вот тут то как раз и происходит выполнение метода RevitAPI в неправильном контексте. Последствия могут быть, а могут и не быть.
Почему же в неправильном? Событие же я могу вызвать в любом месте, главное чтобы обработчик был в правильном.

Вообще изначальная ошибка говорит о том, что вид не подходящий для выбора объектов.
Если вы обработке события Idling отобразить текущий вид, что там будет?
Интересует тип вида и название.
Конечно же первым делом я проверил не сбрасывается ли текущий вид на какой-либо другой. Не сбрасывается.
Название: 3D вид: {3D}
Тип вида: ThreeD