При разработке на управляемых формах 1С программисты часто сталкиваются с необходимостью валидации данных непосредственно в момент их ввода. Казалось бы, событие ОкончаниеВводаТекста идеально подходит для этой задачи: мы можем проверить введенную строку и, если она не удовлетворяет условиям, прервать ввод. Однако на практике установка параметра СтандартнаяОбработка = Ложь часто приводит к неожиданному поведению платформы — вместо тихого возврата к старому значению система выдает диагностическое сообщение «Объект не найден» или «Значение не найдено».
В этой статье мы подробно разберем, почему возникает эта мистическая ошибка, проанализируем внутренние механизмы работы поля ввода и рассмотрим несколько надежных способов решения проблемы.
Рассмотрим стандартную ситуацию: у нас есть реквизит типа Строка, выведенный на форму. Мы хотим, чтобы при вводе некорректного значения (например, неправильного формата телефона или ИНН) платформа игнорировала ввод и оставляла поле в прежнем состоянии. Программист пишет простой код:
&НаКлиенте
Процедура МобильныйТелефонОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, СтандартнаяОбработка)
Если Не ТелефонКорректен(Текст) Тогда
СтандартнаяОбработка = Ложь; // Отменяем стандартное действие
КонецЕсли;
КонецПроцедуры
В этот момент и происходит странное: система выдает ошибку поиска, хотя мы работаем с обычной строкой, а не со ссылочным типом. Выясним причину этого поведения. Когда мы устанавливаем СтандартнаяОбработка = Ложь в обработчике ОкончаниеВводаТекста, мы берем на себя ответственность за результат выбора. Платформа ожидает, что в параметре ДанныеВыбора будет передано то значение, которое должно быть подставлено в поле.
Если СтандартнаяОбработка отключена, а ДанныеВыбора остались равны Неопределено, платформа интерпретирует это как «пользовательский поиск завершен, но ничего не найдено». Именно поэтому появляется системное окно с ошибкой. Такое поведение особенно выражено, если у поля ввода включены свойства История выбора при вводе или Кнопка списка.
Чтобы избежать сообщения об ошибке и корректно восстановить старое значение реквизита, нам нужно явно «подсказать» платформе, что выбор сделан, и этим выбором является текущее значение реквизита (которое еще не успело перезаписаться новым текстом). Посмотрим, как реализовать этот механизм:
&НаКлиенте
Процедура Реквизит1ОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, СтандартнаяОбработка)
// Выполняем проверку введенного текста
Если Текст = "123" Тогда // Пример условия
// 1. Отменяем стандартный поиск платформы
СтандартнаяОбработка = Ложь;
// 2. Создаем список значений, который платформа воспримет как результат выбора
ДанныеВыбора = Новый СписокЗначений;
// 3. Добавляем текущее значение реквизита (то, что было до начала ввода)
// Если это реквизит объекта, используем Объект.ИмяРеквизита
ДанныеВыбора.Добавить(Объект.МобильныйТелефон);
// Теперь платформа увидит, что выбор "состоялся", и ошибка поиска не возникнет
Сообщить("Введены некорректные данные, значение восстановлено!");
КонецЕсли;
КонецПроцедуры
Этот способ позволяет остаться в рамках события завершения ввода, сохраняя логику работы интерфейса. Платформа получит список из одного элемента и автоматически выберет его, не задавая лишних вопросов.
Если логика работы ОкончаниеВводаТекста кажется избыточной или продолжает вести себя нестабильно (например, из-за специфических настроек автоподбора), можно прибегнуть к более простому и надежному способу — проверке в событии ПриИзменении. Однако здесь есть нюанс: на момент срабатывания этого события значение в реквизите уже изменено, и нам нужно знать, что там было «до».
Разберем реализацию с использованием переменной модуля формы для хранения старого значения:
&НаКлиенте
Перем ЗначениеДоИзменения; // Переменная для хранения предыдущего состояния
&НаКлиенте
Процедура РеквизитПриАктивизации(Элемент)
// Запоминаем значение при входе в поле
ЗначениеДоИзменения = Объект.МобильныйТелефон;
КонецПроцедуры
&НаКлиенте
Процедура РеквизитПриИзменении(Элемент)
Если Не ПроверкаПрошла(Объект.МобильныйТелефон) Тогда
// Восстанавливаем из переменной
Объект.МобильныйТелефон = ЗначениеДоИзменения;
Сообщить("Ошибка ввода, возвращено старое значение.");
КонецЕсли;
КонецПроцедуры
Этот метод считается более «безопасным» с точки зрения стабильности платформы, так как он не вмешивается в интерактивные процессы поиска и подбора значений, которые инициирует платформа в событии ОкончаниеВводаТекста.
Часто программисты удивляются: «Почему в справочнике Контрагенты код работает, а в справочнике Номенклатура — нет?». Проанализируем возможные причины различий в поведении:
РежимВыбораИзСписка установлено в значение Да, платформа ведет себя гораздо строже к параметру ДанныеВыбора.ОкончаниеВводаТекста нельзя использовать серверные методы формы с директивой компиляции &НаСервере. Даже если технически вызов проходит, это нарушает событийную модель и может приводить к «зацикливанию» сообщений об ошибках.ОбновлениеТекстаРедактирования. Если оно установлено в значение ПриИзмененииЗначения, это может влиять на момент возникновения события завершения ввода.Использование метода Сообщить() внутри обработчиков ввода может приводить к потере фокуса полем ввода. В некоторых случаях это вызывает повторное срабатывание события ОкончаниеВводаТекста, создавая бесконечный цикл из ошибок «не найдено». Чтобы этого избежать, проанализируем альтернативный подход — использование метода ПоказатьОповещениеПользователя(). Это всплывающее облако не перехватывает фокус и позволяет пользователю комфортно продолжить работу, не закрывая модальные окна.
Резюмируя: если вы решили использовать ОкончаниеВводаТекста для валидации строк, всегда заполняйте параметр ДанныеВыбора, если отменяете стандартную обработку. Это гарантирует отсутствие системных ошибок поиска и обеспечит предсказуемое поведение вашего интерфейса.