Как закрыть форму после нажатия клавиши 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, проверьте, находится ли этот элемент управления в фокусе, прежде чем закрывать форму.

Другие вопросы по тегам