Или окончательное решение цифирьного вопроса.
Преамбула
Ранее мы показывали простые способы, как обеспечить, чтобы в TextBox
можно было ввести только цифры, т.е. целое число (копия), а потом расширили пример до ввода в TextBox
отрицательных (копия) и дробных чисел (копия)
К сожалению, во всех этих примерах есть фатальный недостаток, текст в них все-таки вставить можно, если воспользоваться стандартным контекстным меню или комбинацией клавиш CTRL+V. На уровне простого взаимодействия с формой и контролами это перехватить невозможно, придется несколько извернуться, т.к. для перехвата события «вставить», придется перехватить сообщение Windows WM_PASTE
, которое отправляется окну, или элементу управления окна при выполнении операции вставки. Для Windows, тащемта, однохуйственно, кому отправлять сообщение, форме (окну) или, например, текстовому полю. Т.к. для Windows, и текстовое поле на самом деле окно, просто дочернее, т.е. размещенное в другом окне (форме, в нашем случае). Но это я залез глубоко в бок. Нам нужно добраться до сообщений. А это можно сделать только изнутри самого контрола, но не из событий стандартных контролов, так что будем писать свой!
Постановка задачи: необходимо создать свой контрол на основе текстового поля, который позволяет вводить только числа определенного типа — целые, целые отрицательные, отрицательные и положительные/отрицательные с дробной частью.
Начало
Подключим необходимые пространства имен:
using System.Windows.Forms;
using System.ComponentModel;
using System.Globalization;
Начнем делать свой контрол, наследуемый от TextBox
. Т.е. создадим новый класс:
public class InputDigitControl:TextBox
{
//тут будет код :)
}
Для начала необходимо определить сообщения, которые будем перехватывать. Заводим в классе константы, определяющие коды нужных сообщений:
const int WM_PASTE = 0x0302; //Сообщение "Вставка" (через к.м. и комбинацию клавиш)
const int WM_CHAR = 0x0102; //Сообщение - нажатие алфавитно-цифровой клавиши
WM_CHAR
будет отправлено форме системой только тогда, когда будет нажата алфавитно-цифровая клавиша, его будем перехватывать для отслеживания цифр (и прочего). Правда есть важный нюанс — WM_CHAR
посылается и при нажатии комбинаций клавиш, например Ctrl+C и т.д., а также некоторых клавиш, которые не совсем подходят под понятие «алфавитно-цифровая», например BACKSPACE. Это надо будет учесть.
Анализ ввода с клавиатуры будем производить в функции PreProcessMessage()
, которую переопределим. PreProcessMessage()
вызывается для предварительной обработки входящих сообщений, и нужно будет вернуть true
, если это сообщение было обработано.
Т.е. алгоритм действий таков — мы проверяем входящий символ на соответствие, и, либо пропускаем его дальше (возвращаем base.PreProcessMessage(ref msg)
или false
), либо что-то делаем с содержимым текстового поля, если символ нужен (это понадобится при вводе отрицательных и дробей) и возвращаем true
. Или ничего не делаем, если символ нежелательный, и просто вызываем true
. В последнем случае, символ просто не попадет в поле ввода, т.к. контрол будет думать, что он уже обработан.
Вставку, как я уже говорил выше, тоже нужно будет обработать, но, естественно, несколько иначе, это будем делать в переопределенной функции WndProc()
Под катом еще много
Исходники
Контрол
Тестовое приложение
Репозиторий