Запуск плагина из класса наследованного от IExternalApplication

Автор Тема: Запуск плагина из класса наследованного от IExternalApplication  (Прочитано 9053 раз)

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

Оффлайн shssАвтор темы

  • ADN Club
  • ***
  • Сообщений: 214
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Добрый день!
Хочу запустить плагин из класса где создаю Ribbon панель (есть подозрение, что это невозможно):
Код - C# [Выбрать]
  1. public Result OnStartup(UIControlledApplication application) {
  2. ....//создание PushButton's
  3.         application.ViewActivated += application_ViewActivated;
  4.         return Result.Succeeded;
  5. }
  6. private bool isDocumentActivated = false;
  7. private Document doc = null;
  8. Autodesk.Revit.UI.UIApplication uiApp = null;
  9. void application_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e) {
  10.         isDocumentActivated = true;
  11.         doc = e.Document;
  12.         uiApp = new Autodesk.Revit.UI.UIApplication(doc.Application);
  13. }
  14.  
После открытия активного документа пытаюсь запустить плагин:
Код - C# [Выбрать]
  1. if (isDocumentActivated) {
  2.             string name_addin_button_cmd = "CustomCtrl_%CustomCtrl_%Add-Ins%F4R Prototype%cmd_CreateWalls";
  3.             RevitCommandId id_addin_button_cmd = RevitCommandId.LookupCommandId(name_addin_button_cmd);
  4.             uiApp.PostCommand(id_addin_button_cmd);
  5.  }
  6.  
И получаю ошибку Attempting to create an ExternalEvent outside of a standard API execution
Так как плагин запускает модальное окно и работает с документом, попробовал запустить его напрямую, указывая родителя Revit и передавая в качестве параметра активный документ, но результат тот же.

Есть варианты или же это невозможно?
Спасибо

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

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
У меня получилось вот так:

Код - C# [Выбрать]
  1. private void OnViewActivated(object sender, ViewActivatedEventArgs viewActivatedEventArgs)
  2. {
  3.         var app = sender as UIApplication;
  4.         if (app == null)
  5.                 return;
  6.  
  7.         app.PostCommand(RevitCommandId.LookupCommandId("8c0a9e25-b7c5-421c-a1ab-702f73fa551f"));
  8. }

Оффлайн shssАвтор темы

  • ADN Club
  • ***
  • Сообщений: 214
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
В этом случае мне нужно будет на каждую кнопку делать отдельный проект с отдельным AddInId.
Просто у меня один плагин содержит N-ое количество PushButton-ов

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

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Если нужно просто добавить кнопки на риббон, то поищите в опубликованных статьях библиотечку Виктора Чекалина (через неё все на порядок проще)

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

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Если работать напрямую с API, то можно что-то типа такого написать:
Код - C# [Выбрать]
  1. public Result OnStartup(UIControlledApplication a)
  2. {
  3.         var buttonData = new PushButtonData("<здесь придуманный Вами идентификатор>", "Подпись кнопки",
  4.                                                                                 Assembly.GetExecutingAssembly().Location, "<namespace команды>.<имя класса команды>");
  5.         panel = a.CreateRibbonPanel(Tab.AddIns, "название панельки");
  6.  
  7.        
  8.         panel.AddItem(buttonData);
  9.  
  10.        
  11.         return Result.Succeeded;
  12. }

Оффлайн shssАвтор темы

  • ADN Club
  • ***
  • Сообщений: 214
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Вы меня не совсем правильно поняли.
В общем сделал такой "Костыль":
Код - C# [Выбрать]
  1. [DllImport("user32.dll")]
  2. static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
  3.  
  4. [STAThread]
  5. static void btnWallsPress() {
  6.       Process[] processes = Process.GetProcessesByName("Revit");
  7.       PostMessage(processes[0].MainWindowHandle, WM_KEYDOWN, VK_ESC, 0);
  8.       PostMessage(processes[0].MainWindowHandle, WM_KEYDOWN, VK_ESC, 0);
  9.       PostMessage(processes[0].MainWindowHandle, WM_KEYDOWN, VK_NUMPAD1, 0);
  10. }
  11.  
Ну и соответственно назначил ярлыки каждой кнопке.

Оффлайн shssАвтор темы

  • ADN Club
  • ***
  • Сообщений: 214
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
8c0a9e25-b7c5-421c-a1ab-702f73fa551f
Не понимаю как у Вас так получилось, потому как у меня все равно появляется ошибка Attempting to create an ExternalEvent outside of a standard API execution
Сделал отдельный плагин в иным GUID

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

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Я, все-таки, не понял, зачем нужно эмулировать нажатие кнопок в ревите

8c0a9e25-b7c5-421c-a1ab-702f73fa551f - взял ClientId из одного из .addin файлов

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

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Если нужно навесить быстрые кнопки, то лучше зайти в Параметры\Интерфейс, горячие клавиши, программно тоже туда доступ есть, правда на вскидку не вспомню, где

Оффлайн shssАвтор темы

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

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

  • Administrator
  • *****
  • Сообщений: 1152
  • Карма: 338
  • Skype: alexandr.ignatovich.itc
Т.е., задача сводится к тому, что Revit следит за определенным файлом и если в него вносятся изменения, то нужно внести изменения в модель?

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

Цитировать
This event is raised when it is safe for the API application to access the active document between user interactions. The event is raised only when the Revit UI is in a state where the user could successfully click on an API command button.

Handlers of this event are permitted to make modifications to any document (including the active document), except for documents that are currently in read-only mode.

In order to change a document, you must begin a new transaction for that document. This transaction will appear in the Revit undo stack and may be undone by the Revit user.

This event is invoked between user actions in the Revit UI. If the handler for this event requires a significant amount of processing time, users will perceive a slowdown in the responsiveness of Revit. If the execution for updates can be safely split across multiple calls to this event, the user perception of Revit responsiveness will be improved.

There are two ways to use this event. In the default mode, a single raise of the event will be made each time Revit begins an idle session. Note that when the user is active in the Revit user interface, idle sessions begin whenever the mouse stops moving for a moment or when a command completes. However, if the user is not active in the user interface at all, Revit may not invoke additional idling sessions for quite some time; this means that your application may not be able to take advantage of time when the user leaves the machine completely for a period of time.

In the non-default mode, your application forces Revit to keep the idling session open and to make repeated calls to your event subscriber. In this mode even if the user is totally inactive the Revit session will continue to make Idling calls to your application. However, this can result in performance degradation for the system on which Revit is running because the CPU remains fully engaged in serving Idling events during the Revit application's downtime.

You can indicate the preference for the non-default Idling frequency by calling SetRaiseWithoutDelay()()()() each time the Idling event callback is made. Revit will revert to the default Idling frequency if this method is not called every time in your callback.

Event is not cancellable.

Оффлайн shssАвтор темы

  • ADN Club
  • ***
  • Сообщений: 214
  • Карма: 5
  • Sergey
  • Skype: sergey.s.shevtsov
Спасибо, рассмотрю сейчас этот вариант