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

ADN Club => AutoCAD .NET API => Тема начата: avc от 26-03-2020, 12:27:44

Название: Как отловить нажатие Esc в компоненте WinForms
Отправлено: avc от 26-03-2020, 12:27:44
Есть мой 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 в многострочном текстбоксе, то Автокад вообще завершит работу (спасибо хоть сохранится предложит...)
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: Александр Ривилис от 26-03-2020, 14:51:28
Глянь эту тему: https://forums.autodesk.com/t5/net/datagridview-in-palette-esc-key-problem/m-p/3466730
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: avc от 26-03-2020, 16:55:35
Получается, что это не мой косяк, а палитра перехватывает 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
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: Александр Ривилис от 26-03-2020, 17:03:02
Получается, что это не мой косяк, а палитра перехватывает Esc?
Да.
Попробовал вместо отдельного класса использовать свой контрол как IMessageFilter :
Так и не должно работать.
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: avc от 26-03-2020, 18:18:27
Переписал:
Код - 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 по прежнему вызывается только при создании контрола. Потом никаких вообще событий не ловит :(
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: Александр Ривилис от 26-03-2020, 18:22:15
Подозреваю, что этот фильтр перебивается другим фильтром AutoCAD. Думаю, что нужно подумать в какой момент времени его следует добавлять.
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: avc от 26-03-2020, 18:38:10
Хм. Перекомпилировал и в Автокаде заработало в таком виде. Пошел искать подходящий момент загрузки для иных API...
Спасибо!
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: Дмитрий Загорулькин от 26-03-2020, 18:41:08
В автокаде есть ещё встроенный фильтровальщик: Application.PreTranslateMessage. Может его как-то можно задействовать?
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: Александр Ривилис от 26-03-2020, 18:43:20
В автокаде есть ещё встроенный фильтровальщик: Application.PreTranslateMessage. Может его как-то можно задействовать?
Только нужно убедиться, что и в него это событие попадает. Я натыкался на то, что не все события проходят через этот фильтр.
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: Дмитрий Загорулькин от 26-03-2020, 18:54:21
Да по идее должно попадать... Я думаю, корни проблемы с Esc в том, что палитра - немодальная. К примеру, возьмём палитру свойств объекта. Выбрали объект в чертеже - высветились свойства. Нажали Esc - выделение с объекта снялось, свойства из палитры исчезли. И из-за вот этой автокадовской обработки Esc и перехватывается, наверное. А раз перехватывается, значит и в PreTranslateMessage должно попадать. Но надо тестировать, проверять...
Кстати, в WPF такого не встречал. Может, будет проще на WPF контрол переписать?
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: avc от 26-03-2020, 19:17:39
Нажали Esc - выделение с объекта снялось
Это если не начать редактирование в текстбоксе. А если начать - то вообще ничего не происходит. Ни отмены редактирования, ни отмены выделения, никак событий. А если многострочный текстбокс (тот же самый контрол, одно свойство переключено!!) - происходит выход из Автокада. Круто?!
Может, будет проще на WPF контрол переписать?
ни-ни-ни. Исключено
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: Дмитрий Загорулькин от 26-03-2020, 23:42:09
Странно это. Я WinForms уже давно не трогал, даже проверить не на чем. Но когда-то у меня одна палитра была WinForms с контролом PropertyGrid внутри. В ней значения изменялись при помощи "плавающего" текстбокса. И никаких проблем с Esc вроде не было...
Название: Re: Как отловить нажатие Esc в компоненте WinForms
Отправлено: avc от 27-03-2020, 09:48:37
Да, подтверждаю: PropertyGrid прекрасно ловит Esc на палитре сам, без танцев с бубном. Проблема только с ComboBox и TextBox в режиме Multiline=false