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

14/02/2015

Прерывание вставки экземпляра семейства

Вопрос: В некоторых случаях нам нужно ограничить вставку семейства при использовании метода PromptForFamilyInstancePlacement() и разершить пользователю вставить только одно семейство.

Для реализации, я подписался на событие OnDocumentChanged и пытаюсь прервать операцию вставки после добавления первого экземпляра семейства в модель.

Пока я не могу придумать ничего лучше, чем программно вызывать события нажатии клавиши Esc в окно Revit, но у меня не получается получить идентификатор окна Revit. Хотя в любом случае это выглядит как «костыль».

Можете мне помочь и, возможно, предложить лучшее решение.

Ответ: Определенно, я могу подсказать как получить идентификатор окна Revit.

Я использую вспомогательный класс JtWindowHandle уже несколько лет для определения идентификатора окна и надежной привязки диалоговых окон и форм к главному окну.

Код класса можно найти по ссылке JtWindowHandle.cs.

Пример использования:

Код - C#: [Выделить]
  1.   IWin32Window revit_window
  2.     = new JtWindowHandle(
  3.       ComponentManager.ApplicationWindow );

Обычно я вставляю его в начале выполнения метода [i]Execute[/i] внешней команды.

Я согласен с тем, что программный вызов клавиши Esc это «костыльный» метод, но, к сожалению, официально Revit API содержит методов для достижения желаемого результата.

Ответ: После долгих попыток реализации, мне все же удалось достичь нужного результата.

Сейчас это работает довольно неплохо. Думаю с таким решением можно жить, до тех пор, пока официально не появятся улучшения в работе метода PromptForFamilyInstancePlacement().

Вот что я сделал:

Код - C#: [Выделить]
  1.   private static void OnDocumentChanged(
  2.     object sender,
  3.     DocumentChangedEventArgs e )
  4.   {
  5.     addedInstances.AddRange( e.GetAddedElementIds() );
  6.     if( addedInstances.Count >= 1 )
  7.     {
  8.       if( ComponentManager.ApplicationWindow != IntPtr.Zero )
  9.       {
  10.         WindowsMessaging.PostWindowsMessage(
  11.           (int) ComponentManager.ApplicationWindow,
  12.           WindowsMessaging.WM_KEYDOWN,
  13.           (int) Keys.Escape, 0 );
  14.  
  15.         WindowsMessaging.PostWindowsMessage(
  16.           (int) ComponentManager.ApplicationWindow,
  17.           WindowsMessaging.WM_KEYDOWN,
  18.           (int) Keys.Escape, 0 );
  19.       }
  20.     }
  21.   }
  22.  
  23.   public static class WindowsMessaging
  24.   {
  25.     [DllImport( "User32.dll", EntryPoint = "SendMessage" )]
  26.     public static extern int SendMessage(
  27.       int hWnd, int Msg, int wParam, int lParam );
  28.  
  29.     [DllImport( "User32.dll", EntryPoint = "PostMessage" )]
  30.     public static extern int PostMessage(
  31.       int hWnd, int Msg, int wParam, int lParam );
  32.  
  33.     public const int WM_KEYDOWN = 0x0100;
  34.  
  35.     public static int SendWindowsMessage(
  36.       int hWnd, int Msg, int wParam, int lParam )
  37.     {
  38.       int result = 0;
  39.       if( hWnd > 0 )
  40.         result = SendMessage( hWnd, Msg, wParam, lParam );
  41.  
  42.       return result;
  43.     }
  44.  
  45.     public static int PostWindowsMessage(
  46.       int hWnd, int Msg, int wParam, int lParam )
  47.     {
  48.       int result = 0;
  49.       if( hWnd > 0 )
  50.         result = PostMessage( hWnd, Msg, wParam, lParam );
  51.  
  52.       return result;
  53.     }
  54.   }

Ответ: Поздравляю.

На основе вашего решения, я реализовал код для прерывания выполнения метода PromptForFamilyInstancePlacement() после вставки первого экземпляра в существующей команде CmdPlaceFamilyInstance в примерах The Building Coder.

Я правда не знаю, почему нужно посылать сообщение WM_KEYDOWN дважды.

Но, какова бы не была причина, я подтверждаю, что послав сообщение дважды, код работает, а послав только один раз – нет.

Ответ: Когда вы поместили экземпляр семейства в модель с помощью метода PromptForFamilyInstancePlacement, элемент остается выделенным, до тех пор, пока вы не вставите еще один. Собственно, первое нажатие Esc снимает выделение, а второе нажатие – прерывает команду.

Источник: http://thebuildingcoder.typepad.com/blog/2015/02/sending-escape-to-terminate-a-family-instance-placement-loop.html

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

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