Как закрыть форму после нажатия клавиши ESC, но только если ни один элемент управления не обработал ее?
У меня есть форма, которая закрывается при нажатии клавиши ESC, благодаря KeyPreview
, ProcessKeyEventArgs
, ProcessCmdKey
или что угодно. Но у меня есть элемент управления в этой форме, который делает очень важные вещи, когда нажата ESC (она скрывается), и форма не должна закрываться, когда это происходит.
Элемент управления использует KeyDown
событие и устанавливает SuppressKeyPress
признак true, но это происходит после вышеупомянутого предварительного просмотра ключа формы, таким образом, не имеет никакого эффекта.
Есть какой-то вид KeyPostview?
Как я не закрываю форму, когда элемент управления соответствующим образом использует нажатие клавиши?
Редактировать: Управление ESC - это текстовое поле, встроенное в ListView служанки. Текстовое поле появляется, когда пользователь щелкает ячейку, чтобы включить редакцию. Чтобы проверить новый текст, было бы неплохо ввести ENTER (это уже работает, поскольку фокусируется на чем-то еще). Чтобы отменить издание, ESC кажется наиболее естественным.
4 ответа
Вы соревнуетесь в Big Time за клавишу Escape. Вместе с клавишей Enter это очень важный ключ в стандартном пользовательском интерфейсе Windows. Просто поместите кнопку в форму и установите свойство формы CancelButton для какой-либо другой кнопки, которая высосет нажатие клавиши для этой кнопки.
Чтобы конкурировать с этим, вы должны создать элемент управления, который сообщает Winforms, что вы действительно думаете, что клавиша Escape более важна. Это требует переопределения свойства IsInputKey. Как это:
using System;
using System.Windows.Forms;
class MyTexBox : TextBox {
protected override bool IsInputKey(Keys keyData) {
if (keyData == Keys.Escape) return true;
return base.IsInputKey(keyData);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyData == Keys.Escape) {
this.Text = ""; // for example
e.SuppressKeyPress = true;
return;
}
base.OnKeyDown(e);
}
}
ОК - это работает:
class CustomTB : TextBox
{
public CustomTB()
: base()
{
CustomTB.SuppressEscape = false;
}
public static bool SuppressEscape { get; set; }
protected override void OnKeyDown(KeyEventArgs e)
{
CustomTB.SuppressEscape = (e.KeyCode == Keys.Escape);
base.OnKeyUp(e);
}
}
В вашей форме:
public Form1()
{
InitializeComponent();
this.KeyPreview = true;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape && !CustomTB.SuppressEscape)
{
this.Close();
}
CustomTB.SuppressEscape = false;
}
Основная проблема заключается в том, что метод Dispose формы вызывается при вызове Close, поэтому форма закрывается, и с этим ничего не поделаешь.
Я бы обошел это, если бы UserControl реализовывал интерфейс маркера, скажем ISuppressEsc. Затем обработчик формы KeyUp может найти фокусированный в данный момент элемент управления и отменить закрытие, если фокусированный элемент управления реализует ISuppressEsc. Помните, что вам придется проделать дополнительную работу, чтобы найти сфокусированный элемент управления, если он может быть вложенным.
public interface ISuppressEsc
{
// marker interface, no declarations
}
public partial class UserControl1 : UserControl, ISuppressEsc
{
public UserControl1()
{
InitializeComponent();
}
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
textBox1.Text = DateTime.Now.ToLongTimeString();
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
KeyPreview = true;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
var activeCtl = ActiveControl;
if (!(activeCtl is ISuppressEsc) && e.KeyCode == Keys.Escape)
{
Close();
}
}
}
Можете ли вы проверить, какой элемент управления имеет фокус в первую очередь? Если в вашей форме есть только один элемент управления, имеющий отношение к клавише escape, проверьте, находится ли этот элемент управления в фокусе, прежде чем закрывать форму.