Как отловить нажатие Esc в компоненте WinForms

Автор Тема: Как отловить нажатие Esc в компоненте WinForms  (Прочитано 651 раз)

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

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

  • ADN Club
  • *****
  • Сообщений: 523
  • Карма: 100
    • Мои плагины к Автокаду
Есть мой UserControl на котором есть комбобоксы и текстбоксы. Размещаю его в палитре Автокада. Пытаюсь отработать кнопку Esc, чтоб пользователь во время редактирования текстов в текстбоксах мог вернуть исходное значение.
Код - C# [Выбрать]
  1.     protected void Tb_KeyDown(object sender, KeyEventArgs e)
  2.     {
  3.       if (e.KeyCode == Keys.Escape && sender is Control con)
  4.       {
  5.         // тут делаю нужную мне работу с con
  6.        ....
  7.         e.Handled = true; // ESC надо в любом случае заблокировать. иначе Автокад завершит работу!!
  8.       }
  9.     }
Так вот этот обработчик вызывается только у текстбоксов и только если они многострочные. Во всех остальных случаях Esc проглатывается Автокадом (или кем?) и Tb_KeyDown вообще не вызывается. Кто нибудь сталкивался с такой загадкой?
И, кстати, еще сюрприз - если не перехватить Esc в многострочном текстбоксе, то Автокад вообще завершит работу (спасибо хоть сохранится предложит...)

Отмечено как Решение avc 26-03-2020, 18:38:21

Оффлайн Александр Ривилис

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

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

  • ADN Club
  • *****
  • Сообщений: 523
  • Карма: 100
    • Мои плагины к Автокаду
Получается, что это не мой косяк, а палитра перехватывает Esc? Тогда почему некоторые контролы все-таки получают нажатие? Загадочно...
Не очень умею с этими фильтрами работать. Попробовал вместо отдельного класса использовать свой контрол как IMessageFilter :
Код - C# [Выбрать]
  1. internal partial class AvcControl : UserControl, IMessageFilter
  2.   {
  3.    ....
  4.    
  5.    public AvcControl()
  6.     {
  7.       InitializeComponent();
  8.       ....
  9.       System.Windows.Forms.Application.AddMessageFilter(this);
  10.     }
  11.  
  12.     public new void Dispose()
  13.     {
  14.       System.Windows.Forms.Application.RemoveMessageFilter(this);
  15.       base.Dispose();
  16.     }
  17.        
  18.     private const int WM_KEYDOWN = 0x100;
  19.     bool IMessageFilter.PreFilterMessage(ref Message m)
  20.     {
  21.       if (m.Msg != WM_KEYDOWN) return false; // до этой строки дело доходит
  22.       if (loading || IsDisposed || !Visible || !ContainsFocus) return false; // а до сюда не доходит никогда
  23.       Keys kc = (Keys)(int)m.WParam & Keys.KeyCode;
  24.       if (m.Msg == WM_KEYDOWN && kc == Keys.Escape)
  25.       {
  26.         Control acvive = ActiveControl;
  27.         if (acvive is TextBox || acvive is ComboBox)
  28.         {
  29.           Esc(acvive); // Откат изменений в поле
  30.           return true;
  31.         }
  32.       }
  33.       return false;
  34.     }
Не получилось. Какие то события получает, но все WM_KEYDOWN каким-то образом проходят мимо, сразу вызывается OnKeyDown

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 11009
  • Карма: 1396
  • Рыцарь ObjectARX
  • Skype: rivilis
Получается, что это не мой косяк, а палитра перехватывает Esc?
Да.
Попробовал вместо отдельного класса использовать свой контрол как IMessageFilter :
Так и не должно работать.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 523
  • Карма: 100
    • Мои плагины к Автокаду
Переписал:
Код - C# [Выбрать]
  1.   internal partial class AvcControl : UserControl
  2.   {
  3.     readonly KeyMessageFilter _filter;
  4.  
  5.     public AvcControl()
  6.     {
  7.       InitializeComponent();
  8.       _filter = new KeyMessageFilter(this);
  9.       System.Windows.Forms.Application.AddMessageFilter(_filter);
  10.     }
  11.  
  12.     public new void Dispose()
  13.     {
  14.       System.Windows.Forms.Application.RemoveMessageFilter(_filter);
  15.       base.Dispose();
  16.     }
  17.        
  18.         protected void Esc(Control sender)
  19.     {
  20.                 .....
  21.     }
  22.        
  23.     class KeyMessageFilter : IMessageFilter
  24.     {
  25.       readonly AvcControl _owner;
  26.       internal KeyMessageFilter(AvcControl owner) { _owner = owner; }
  27.  
  28.       private const int WM_KEYDOWN = 0x100;
  29.       bool IMessageFilter.PreFilterMessage(ref Message m)
  30.       {
  31.         if (m.Msg != WM_KEYDOWN) return false;
  32.         if (_owner == null || _owner.IsDisposed || !_owner.Visible || !_owner.ContainsFocus) return false;
  33.         Keys kc = (Keys)(int)m.WParam & Keys.KeyCode;
  34.         if (m.Msg == WM_KEYDOWN && kc == Keys.Escape)
  35.         {
  36.           Control acvive = _owner.ActiveControl;
  37.           if (acvive is TextBox || acvive is ComboBox)
  38.           {
  39.             _owner.Esc(acvive);
  40.             return true;
  41.           }
  42.         }
  43.         return false;
  44.       }
  45.     }
PreFilterMessage по прежнему вызывается только при создании контрола. Потом никаких вообще событий не ловит :(

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 11009
  • Карма: 1396
  • Рыцарь ObjectARX
  • Skype: rivilis
Подозреваю, что этот фильтр перебивается другим фильтром AutoCAD. Думаю, что нужно подумать в какой момент времени его следует добавлять.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • *****
  • Сообщений: 523
  • Карма: 100
    • Мои плагины к Автокаду
Хм. Перекомпилировал и в Автокаде заработало в таком виде. Пошел искать подходящий момент загрузки для иных API...
Спасибо!

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2252
  • Карма: 612
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
В автокаде есть ещё встроенный фильтровальщик: Application.PreTranslateMessage. Может его как-то можно задействовать?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 11009
  • Карма: 1396
  • Рыцарь ObjectARX
  • Skype: rivilis
В автокаде есть ещё встроенный фильтровальщик: Application.PreTranslateMessage. Может его как-то можно задействовать?
Только нужно убедиться, что и в него это событие попадает. Я натыкался на то, что не все события проходят через этот фильтр.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2252
  • Карма: 612
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Да по идее должно попадать... Я думаю, корни проблемы с Esc в том, что палитра - немодальная. К примеру, возьмём палитру свойств объекта. Выбрали объект в чертеже - высветились свойства. Нажали Esc - выделение с объекта снялось, свойства из палитры исчезли. И из-за вот этой автокадовской обработки Esc и перехватывается, наверное. А раз перехватывается, значит и в PreTranslateMessage должно попадать. Но надо тестировать, проверять...
Кстати, в WPF такого не встречал. Может, будет проще на WPF контрол переписать?

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

  • ADN Club
  • *****
  • Сообщений: 523
  • Карма: 100
    • Мои плагины к Автокаду
Нажали Esc - выделение с объекта снялось
Это если не начать редактирование в текстбоксе. А если начать - то вообще ничего не происходит. Ни отмены редактирования, ни отмены выделения, никак событий. А если многострочный текстбокс (тот же самый контрол, одно свойство переключено!!) - происходит выход из Автокада. Круто?!
Может, будет проще на WPF контрол переписать?
ни-ни-ни. Исключено

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2252
  • Карма: 612
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Странно это. Я WinForms уже давно не трогал, даже проверить не на чем. Но когда-то у меня одна палитра была WinForms с контролом PropertyGrid внутри. В ней значения изменялись при помощи "плавающего" текстбокса. И никаких проблем с Esc вроде не было...

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

  • ADN Club
  • *****
  • Сообщений: 523
  • Карма: 100
    • Мои плагины к Автокаду
Да, подтверждаю: PropertyGrid прекрасно ловит Esc на палитре сам, без танцев с бубном. Проблема только с ComboBox и TextBox в режиме Multiline=false