Прерывание вставки экземпляра семейства
Вопрос: В некоторых случаях нам нужно ограничить вставку семейства при использовании метода PromptForFamilyInstancePlacement() и разершить пользователю вставить только одно семейство.
Для реализации, я подписался на событие OnDocumentChanged и пытаюсь прервать операцию вставки после добавления первого экземпляра семейства в модель.
Пока я не могу придумать ничего лучше, чем программно вызывать события нажатии клавиши Esc в окно Revit, но у меня не получается получить идентификатор окна Revit. Хотя в любом случае это выглядит как «костыль».
Можете мне помочь и, возможно, предложить лучшее решение.
Ответ: Определенно, я могу подсказать как получить идентификатор окна Revit.
Я использую вспомогательный класс JtWindowHandle уже несколько лет для определения идентификатора окна и надежной привязки диалоговых окон и форм к главному окну.
Код класса можно найти по ссылке JtWindowHandle.cs.
Пример использования:
- IWin32Window revit_window
- = new JtWindowHandle(
- ComponentManager.ApplicationWindow );
Обычно я вставляю его в начале выполнения метода [i]Execute[/i] внешней команды.
Я согласен с тем, что программный вызов клавиши Esc это «костыльный» метод, но, к сожалению, официально Revit API содержит методов для достижения желаемого результата.
Ответ: После долгих попыток реализации, мне все же удалось достичь нужного результата.
Сейчас это работает довольно неплохо. Думаю с таким решением можно жить, до тех пор, пока официально не появятся улучшения в работе метода PromptForFamilyInstancePlacement().
Вот что я сделал:
- private static void OnDocumentChanged(
- object sender,
- DocumentChangedEventArgs e )
- {
- addedInstances.AddRange( e.GetAddedElementIds() );
- if( addedInstances.Count >= 1 )
- {
- if( ComponentManager.ApplicationWindow != IntPtr.Zero )
- {
- WindowsMessaging.PostWindowsMessage(
- (int) ComponentManager.ApplicationWindow,
- WindowsMessaging.WM_KEYDOWN,
- (int) Keys.Escape, 0 );
- WindowsMessaging.PostWindowsMessage(
- (int) ComponentManager.ApplicationWindow,
- WindowsMessaging.WM_KEYDOWN,
- (int) Keys.Escape, 0 );
- }
- }
- }
- public static class WindowsMessaging
- {
- [DllImport( "User32.dll", EntryPoint = "SendMessage" )]
- public static extern int SendMessage(
- int hWnd, int Msg, int wParam, int lParam );
- [DllImport( "User32.dll", EntryPoint = "PostMessage" )]
- public static extern int PostMessage(
- int hWnd, int Msg, int wParam, int lParam );
- public const int WM_KEYDOWN = 0x0100;
- public static int SendWindowsMessage(
- int hWnd, int Msg, int wParam, int lParam )
- {
- int result = 0;
- if( hWnd > 0 )
- result = SendMessage( hWnd, Msg, wParam, lParam );
- return result;
- }
- public static int PostWindowsMessage(
- int hWnd, int Msg, int wParam, int lParam )
- {
- int result = 0;
- if( hWnd > 0 )
- result = PostMessage( hWnd, Msg, wParam, lParam );
- return result;
- }
- }
Ответ: Поздравляю.
На основе вашего решения, я реализовал код для прерывания выполнения метода PromptForFamilyInstancePlacement() после вставки первого экземпляра в существующей команде CmdPlaceFamilyInstance в примерах The Building Coder.
Я правда не знаю, почему нужно посылать сообщение WM_KEYDOWN дважды.
Но, какова бы не была причина, я подтверждаю, что послав сообщение дважды, код работает, а послав только один раз – нет.
Ответ: Когда вы поместили экземпляр семейства в модель с помощью метода PromptForFamilyInstancePlacement, элемент остается выделенным, до тех пор, пока вы не вставите еще один. Собственно, первое нажатие Esc снимает выделение, а второе нажатие – прерывает команду.
Обсуждение: http://adn-cis.org/forum/index.php?topic=1863
Опубликовано 14.02.2015