Страницы

Поиск по вопросам

воскресенье, 1 декабря 2019 г.

Как создать диалог, который закрывается при нажатии Esc?

#c_sharp #winforms


Как создать форму/диалог в WinForms, который закрывается при нажатии Esc, независимо
от того в каком из контролов находится фокус? И как вернуть данные из диалога?
    


Ответы

Ответ 1



В том редком случае, если на форме нет кнопок вообще - что, на мой взгляд, редкость для диалога, вам стоит воспользоваться решением из соседних ответов. Если на форме есть как минимум одна кнопка, её закрывающая, то стоит использовать стандартный механизм, описанный ниже. Гораздо более простой способ сделать кнопку, реагирующую на Esc - это задать свойство Form.CancelButton. Достаточно лишь бросить кнопку с надписью "Отмена" на форму, открыть свойства формы, и выбрать кнопку в списке CancelButton: После этого эта кнопка будет нажиматься по Esc вне зависимости от текущего активного контрола. Это действие так же автоматически задаст DialogResult = DialogResult.Cancel в свойствах кнопки, что вызовет закрытие формы по нажатию либо на Esc, либо напрямую на кнопку. Подробно эта тема, как и связанные с ней, рассмотрена в MSDN: Практическое руководство. Создание кнопки "Отмена" в Windows Forms Соответствующее свойство для кнопки по умолчанию - Form.AcceptButton - задает точно такое же поведение для Enter. В отличие от CancelButton, задание AcceptButton в дизайнере не выставляет DialogResult у выбранной кнопки, так что при необходимости автоматического закрытия по Enter придется задать это свойство вручуню. Что делать, если на диалоге нет кнопки Cancel? например, диалог вообще не подразумевает отмены действия. Т.к. на диалоге (по крайней мере на диалоговых окнах WinForms, которые обсуждаются в этом вопросе) есть хотя бы одна кнопка, то ее и стоит выбрать и как AcceptButton, и как CancelButton, обеспечив ее срабатывание и по Enter, и по Esc.

Ответ 2



По умолчанию, форма, если содержит хотя бы один дочерний контрол, игнорирует обработку клавиш, даже если вы подписались на соответствующие события. Это поведение можно поменять изменив свойство формы KeyPreview = true (по умолчанию false). После этого события формы будут срабатывать на нажатия клавиш и вызывать соответствующие обработчики. Рабочий пример. В конструкторе для проверки можно накидать на форму произвольных контролов и поиграть со значением указанного свойства. Для вызова в режиме диалога все тоже самое, но добавить присваивание значения свойству DialogResult. public partial class Form1 : Form { public Form1() { InitializeComponent(); this.KeyPreview = true; this.KeyDown += Form1_KeyDown; } private void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyData == Keys.Escape) { ((Form1)sender).Close(); } } }

Ответ 3



Например, надо создать диалог, который возвращает DialogResult.Cancel, если нажали Esc или кнопку закрытия окна; DialogResult.OK и значение ключа, если нажали Enter в поле ввода. Для перехвата нажатий можно использовать KeyPreview, но он работает не всегда. Пример в конце ответа. Поэтому лучше переопределить метод ProcessCmdKey. using System.Windows.Forms; class Dialog : Form { public int Key { get; private set; } public Dialog() { var tb = new TextBox() { Parent = this }; tb.KeyDown += (s, e) => { if (e.KeyCode == Keys.Enter && tb.Text.Contains("1")) { this.Key = DateTime.Now.Millisecond; this.DialogResult = DialogResult.OK; this.Close(); } }; } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { var ret = base.ProcessCmdKey(ref msg, keyData); if (keyData == Keys.Escape) { this.DialogResult = DialogResult.Cancel; this.Close(); ret = true; } return ret; } } Использовать диалог можно так var d = new Dialog(); if(d.ShowDialog() == DialogResult.OK) Console.WriteLine(d.Key); // вывести значение ключа KeyPreview не всегда подходит. Например, после открытия формы первое нажатие Key.Left не перехватывается. public partial class Form1 : Form { public Form1() { var t = new TextBox() { Parent = this }; var l = new Label() { Parent = this }; this.KeyPreview = true; this.KeyDown += Form1_KeyDown; this.Shown += (s, e) => l.Focus(); } private void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyData == Keys.Left) { ((Form1)sender).Close(); } } } Дополнение 4: Для того, чтобы получить информацию о Windows окнах (windows styles, class name, windows rect и т.д.), можно использовать HWndSpy - исходный код тут. У всплывающих окон, диалогов, контекстных меню и т.д., в значении Windows Styles указывается WS_POPUP. Дополнение 3: Диалоговое окно или диалог - это окно для вывода информации и (или) получения ответа от пользователя. Меню или контекстное меню - это окно, которое не содержит кнопки OK и/или Cancel и закрывается при нажатии Esc. Дополнение 2: Форма/диалог/всплывающее окно, далее диалог - это окно с определенным поведением. Дополнение 1: Не во всех диалогах есть кнопки. Например, если нажать Win+S в Windows 10, то откроется диалог, в котором нет кнопок OK и Cancel.

Комментариев нет:

Отправить комментарий