При разработке интерфейсов на обычных формах 1С (например, в конфигурации «Управление торговлей 10.3») часто возникает задача валидации пользовательского ввода непосредственно в табличной части или табличном поле. Типичный сценарий: пользователь вводит значение в ячейку (например, адрес электронной почты), система проверяет его на корректность и, если найдена ошибка, должна предупредить пользователя и оставить курсор в этой же ячейке в режиме редактирования для исправления.
Однако при попытке реализовать такую логику в событии ПриИзменении разработчики сталкиваются с тем, что курсор все равно переходит в следующую колонку строки. Разберем причины такого поведения платформы и рассмотрим надежные способы решения задачи.
Проанализируем механику работы табличного поля. Событие ПриИзменении у элемента управления ячейки срабатывает в момент, когда редактирование значения уже завершено (пользователь нажал Enter, Tab или кликнул в другую ячейку). После выполнения кода процедуры платформа запускает внутренний алгоритм навигации — переводит фокус на следующий элемент формы или следующую колонку строки согласно порядку обхода.
По этой причине прямое присвоение ЭлементыФормы.ТабличноеПоле.ТекущаяКолонка = НужнаяКолонка; внутри процедуры ПриИзменении просто перезаписывается последующим системным переходом платформы. Дополнительно ситуацию осложняет модальное окно Предупреждение(): оно перехватывает системный фокус, сбивая внутреннее состояние ввода ячейки.
Если требуется обязательно проверить значение сразу при выходе из ячейки и вернуть пользователя обратно, наиболее эффективным решением является отложенный вызов через процедуру ожидания. Это позволяет дождаться, пока платформа завершит штатную навигацию, после чего программно активизировать нужную строку, колонку и открыть режим редактирования.
Рассмотрим пошаговую реализацию этого алгоритма:
ПриИзменении выполним проверку и подключим однократный обработчик ожидания.ИзменитьСтроку().Посмотрим на пример программного кода модуля формы:
Перем мОшибочнаяСтрока;
Перем мОшибочнаяКолонка;
Процедура таблЭлектрПочтаКолонкаЭлектрПочтаПриИзменении(Элемент)
ТекСтрока = ЭлементыФормы.таблЭлектрПочта.ТекущиеДанные;
Если ТекСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
ТекЗначение = СокрЛП(ТекСтрока.КолонкаЭлектрПочта);
Если Найти(ТекЗначение, " ") > 0 Тогда
Сообщить("Адрес электронной почты не может содержать пробелы!", СтатусСообщения.Важное);
// Сохраняем координаты ячейки
мОшибочнаяСтрока = ТекСтрока;
мОшибочнаяКолонка = ЭлементыФормы.таблЭлектрПочта.Колонки.КолонкаЭлектрПочта;
// Подключаем однократный обработчик с минимальной задержкой
ПодключитьОбработчикОжидания("ВернутьФокусВЯчейку", 0.1, Истина);
КонецЕсли;
КонецПроцедуры
Процедура ВернутьФокусВЯчейку() Экспорт
// Активизируем табличное поле на форме
ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.таблЭлектрПочта;
// Устанавливаем строку и колонку
Если мОшибочнаяСтрока <> Неопределено Тогда
ЭлементыФормы.таблЭлектрПочта.ТекущаяСтрока = мОшибочнаяСтрока;
КонецЕсли;
Если мОшибочнаяКолонка <> Неопределено Тогда
ЭлементыФормы.таблЭлектрПочта.ТекущаяКолонка = мОшибочнаяКолонка;
КонецЕсли;
// Переводим ячейку в режим редактирования
ЭлементыФормы.таблЭлектрПочта.ИзменитьСтроку();
мОшибочнаяСтрока = Неопределено;
мОшибочнаяКолонка = Неопределено;
КонецПроцедуры
Обратите внимание: вместо блокирующего модального метода Предупреждение() рекомендуется использовать Сообщить(), чтобы не ломать последовательность обработки событий пользовательского интерфейса.
В платформе 1С штатным механизмом запрета перехода при невалидных данных является событие табличного поля ПередОкончаниемРедактирования. Оно срабатывает, когда пользователь пытается завершить редактирование всей строки (нажимает Enter в последней колонке, кликает на другую строку или вне таблицы).
Разберем, как применить этот механизм для контроля конкретной колонки:
Процедура таблЭлектрПочтаПередОкончаниемРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования, Отказ)
Если ОтменаРедактирования Тогда
Возврат;
КонецЕсли;
ТекДанные = Элемент.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Если Найти(СокрЛП(ТекДанные.КолонкаЭлектрПочта), " ") > 0 Тогда
Сообщить("Некорректный E-Mail: адрес не должен содержать пробелов.", СтатусСообщения.Внимание);
// Возвращаем фокус на ошибочную колонку
Элемент.ТекущаяКолонка = Элемент.Колонки.КолонкаЭлектрПочта;
// Запрещаем выход из режима редактирования строки
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
В этом случае пользователь сможет перемещаться между колонками внутри одной строки, но программа гарантированно не позволит сохранить строку или перейти к другой записи, пока ошибка в поле почты не будет устранена.
Чтобы при установке ТекущаяКолонка ячейка сразу переходила в активный ввод без необходимости повторного двойного клика мышью, настроим свойство колонки РежимРедактирования:
РежимРедактирования (или EditMode).РежимРедактированияКолонки.ВходПриВводе) или Непосредственно (РежимРедактированияКолонки.Непосредственно).Такая настройка гарантирует быстрое открытие редактора поля ввода при попадании на колонку программно или с клавиатуры.