Как предотвратить нажатие клавиши Backspace в TextBox?

Я хочу подавить нажатие клавиши в TextBox. Чтобы подавить все нажатия клавиш, кроме Backspace, я использую следующее:

    private void KeyBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {
        e.Handled = true;
    }

Однако я хочу подавлять нажатия клавиш только тогда, когда нажата клавиша Backspace. Я использую следующее:

        if (e.Key == System.Windows.Input.Key.Back)
        {
            e.Handled = true;
        }

Однако это не работает. Символ за началом выделения по-прежнему удаляется. Я получаю «ИСТИНА» на выходе, поэтому клавиша «Назад» распознается. Как я могу запретить пользователю нажимать клавишу Backspace? (Моя причина этого в том, что в некоторых случаях я хочу удалить слова вместо символов, и поэтому мне нужно самому обрабатывать нажатие клавиши «Назад»).)


person msbg    schedule 09.03.2013    source источник
comment
Разве нет такого события, как PreviewKeyDown?   -  person Honza Brestan    schedule 10.03.2013
comment
Silverlight для Windows Phone не содержит реализации PreviewKeyDown.   -  person Den Delimarsky    schedule 10.03.2013


Ответы (6)


Это правда, что нет простого способа справиться с этим сценарием, но это возможно.

Вам нужно создать некоторые переменные-члены в классе для хранения состояния вводимого текста, положения курсора и состояния нажатия клавиши возврата при переходе между событиями KeyDown, TextChanged и KeyUp.

Код должен выглядеть примерно так:

    string m_TextBeforeTheChange;
    int m_CursorPosition = 0;
    bool m_BackPressed = false;

    private void KeyBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {
        m_TextBeforeTheChange = KeyBox.Text;
        m_BackPressed = (e.Key.Equals(System.Windows.Input.Key.Back)) ? true : false;
    }

    private void KeyBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        if (m_BackPressed)
        {
            m_CursorPosition = KeyBox.SelectionStart;
            KeyBox.Text = m_TextBeforeTheChange;
        }
    }

    private void KeyBox_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
        KeyBox.SelectionStart = (m_BackPressed) ? m_CursorPosition + 1 : KeyBox.SelectionStart;
    }
person Rob.Kachmar    schedule 10.03.2013
comment
Принятое решение не самое лучшее. Лучшее предложение ниже с использованием e.SuppressKeyPress - person tofo; 01.11.2016

Просто установите e.SuppressKeyPress = true (в событии KeyDown), если вы хотите подавить нажатие клавиши. Например, запретите клавише возврата изменять текст в текстовом поле, используя следующий код:

private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Back)
    {
        e.SuppressKeyPress = true;
    }
}

Обратите внимание, что если вы попробуете это сделать в обработчике txtBox1_KeyUp(), это не сработает (поскольку KeyDown уже обработал событие для TextBox).

person Huy Nguyen    schedule 05.08.2013

В Silverlight нет возможности обрабатывать системные ключевые события, такие как backspace. Таким образом, вы можете обнаружить его, но не обрабатывать вручную.

person Den Delimarsky    schedule 09.03.2013

Это требует, чтобы мы сохранили значение текстового поля до события нажатия клавиши. К сожалению, backspace обрабатывается до того, как это событие будет запущено, поэтому мы должны захватить его до того, как это произойдет, а затем мы можем обновить его снова после обработки события нажатия клавиши.

    private string textBeforeChange;

    private void TextBox1_OnKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Back)
        {
            e.Handled = true;
            textBox1.Text = textBeforeChange;
        }
    }

    private void TextBox1_OnKeyUp(object sender, KeyEventArgs e)
    {
        textBeforeChange = textBox1.Text;
    }

    private void MainPage_OnLoaded(object sender, RoutedEventArgs e)
    {
        textBox1.AddHandler(TextBox.KeyDownEvent, new KeyEventHandler(TextBox1_OnKeyDown), true);
        textBox1.AddHandler(TextBox.KeyUpEvent, new KeyEventHandler(TextBox1_OnKeyUp), true);
        textBox1.AddHandler(TextBox.ManipulationStartedEvent, new EventHandler<ManipulationStartedEventArgs>(TextBox1_OnManipulationStarted), true);
    }

    private void TextBox1_OnManipulationStarted(object sender, ManipulationStartedEventArgs e)
    {
        textBeforeChange = textBox1.Text;
    }
person Jake Anderson    schedule 11.03.2013

Это то, что я придумал, чтобы удалить предыдущее (CtrlBackspace) и следующее слово (CtrlУдалить), обработка нескольких последующих пробельных символов (0x09, 0x20, 0xA0):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DeleteWord
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            // Tab, space, line feed
            char[] whitespace = {'\x09', '\x20', '\xA0'};
            string text = textBox1.Text;
            int start = textBox1.SelectionStart;

            if ((e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) && textBox1.SelectionLength > 0)
            {
                e.SuppressKeyPress = true;
                textBox1.Text = text.Substring(0, start) + text.Substring(start + textBox1.SelectionLength);
                textBox1.SelectionStart = start;
                return;
            }

            else if (e.KeyCode == Keys.Back && e.Control)
            {
                e.SuppressKeyPress = true;

                if (start == 0) return;

                int pos = Math.Max(text.LastIndexOfAny(whitespace, start - 1), 0);

                while (pos > 0)
                {
                    if (!whitespace.Contains(text[pos]))
                    {
                        pos++;
                        break;
                    }
                    pos--;
                }

                textBox1.Text = text.Substring(0, pos) + text.Substring(start);
                textBox1.SelectionStart = pos;
            }
            else if (e.KeyCode == Keys.Delete && e.Control)
            {
                e.SuppressKeyPress = true;

                int last = text.Length - 1;

                int pos = text.IndexOfAny(whitespace, start);
                if (pos == -1) pos = last + 1;

                while (pos <= last)
                {
                    if (!whitespace.Contains(text[pos])) break;
                    pos++;
                }

                textBox1.Text = text.Substring(0, start) + text.Substring(pos);
                textBox1.SelectionStart = start;
            }
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.Tab)
            {
                textBox1.Paste("\t");
                return true;
            }
            else if (keyData == (Keys.Shift | Keys.Tab))
            {
                textBox1.Paste("\xA0");
                return true;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

    }
}

Спасибо Хай Нгуену за e.SuppressKeyPress = true;!

Если есть выделение, и Delete, и Backspace удалят выделение, независимо от клавиш-модификаторов (вы не получите этот уродливый прямоугольный символ, удерживая Ctrl)

Кажется, это работает и для таких символов, как ????, хотя это может не иметь особого смысла (разве этот символ не целое слово?)

person CodeManX    schedule 22.02.2014

Это простое решение, которое работает для меня.

private void MyTxtbox_Keypress(object sender, KeyPressEventArgs e)
{
    if (e.KeyChar == '\b')
    {
        e.Handled = true;

        return;
    }
}
person salkow    schedule 27.09.2019