Разработчики, начинающие активно работать с управляемыми формами в 1С:Предприятии, рано или поздно сталкиваются со специфическим поведением поля ввода при попытке обработать текст непосредственно в процессе его набора. Казалось бы, событие ИзменениеТекстаРедактирования создано именно для этого: оно перехватывает ввод каждого символа, работу с буфером обмена и отмену действий. Однако на практике любая попытка написать в обработчике код сложнее проверки на пустую строку часто приводит к тому, что вводимый текст сбрасывается, курсор перескакивает, а пользователь теряет набранные данные.
В рамках этой статьи мы подробно разберем, почему платформа ведет себя подобным образом, какие скрытые механизмы вызывают эти «аномалии», как правильно настроить свойства элементов формы и как обойти строгие ограничения платформы на серверные вызовы.
Выясним причину, по которой обычное чтение или минимальный анализ параметра Текст в обработчике события ломает процесс ввода. Дело в том, что событие ИзменениеТекстаРедактирования срабатывает на каждое изменение текста в поле ввода пользователем. Если внутри обработчика мы пытаемся изменить значение другого реквизита формы или как-то повлиять на состояние элементов (например, сделать видимым или доступным какой-то элемент, изменить высоту поля, заполнить вспомогательный реквизит), платформа инициирует принудительное обновление и перерисовку управляемой формы.
Во время перерисовки формы система пытается актуализировать данные во всех полях. Поведение поля ввода в этот момент регулируется важнейшим свойством — ОбновлениеТекстаРедактирования (EditTextUpdate):
ПриИзменении еще не произошло, ввод не завершен). Пытаясь синхронизировать отображение, платформа перезаписывает набранный пользователем текст старым значением из реквизита. Текст «откатывается» назад или выделяется, делая дальнейший набор невозможным.ОбновлениеТекстаРедактирования значение Не использовать, платформа прекратит насильно обновлять текст в поле ввода при перерисовках формы во время набора. Вводимые символы перестанут исчезать, и мы сможем безопасно выполнять анализ строки прямо «на лету»!Начиная с современных версий платформы 1С:Предприятие 8.3 (активно фиксируется начиная с релиза 8.3.15), в синтакс-помощнике появилось жесткое предупреждение: в обработчике события ИзменениеТекстаРедактирования запрещено использовать серверные методы с директивой компиляции &НаСервере, а также изменять свойства, которые могут привести к серверному вызову.
Если нарушить это правило, платформа сгенерирует исключение или заблокирует интерфейс. Но опасность кроется в неявных вызовах. К ним относятся:
Проанализируем ситуацию: как же нам связаться с сервером, если при наборе текста нужно, например, динамически подобрать данные из информационной базы? Для этого существует классический паттерн разработки — использование обработчика ожидания (техника Debounce).
Чтобы не перегружать сервер частыми запросами при вводе каждой буквы и обойти ограничение на контекстные вызовы, мы можем запускать серверную процедуру с небольшой задержкой (например, 0.3 - 0.5 секунды) после того, как пользователь приостановил ввод. Каждое нажатие клавиши будет сбрасывать таймер и запускать его заново.
Посмотрим на пример реализации такого механизма. Допустим, нам необходимо динамически менять высоту многострочного поля ввода в зависимости от количества введенного текста (символов перевода строки). Разберем этот код по шагам:
&НаКлиенте
ПеременныеФормы = Новый Структура("КоличествоСтрок, ТекстДляАнализа");
&НаКлиенте
Процедура Реквизит1ИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
// Сохраняем текст во временную переменную модуля для последующего анализа
ПеременныеФормы.Вставить("ТекстДляАнализа", Текст);
// Сбрасываем предыдущий таймер и подключаем новый на 100 миллисекунд.
// Это гарантирует, что код анализа выполнится только после микропаузы в наборе.
ОтключитьОбработчикОжидания("ВыполнитьАнализТекста");
ПодключитьОбработчикОжидания("ВыполнитьАнализТекста", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьАнализТекста() Экспорт
Текст = ПеременныеФормы.ТекстДляАнализа;
СтрДлинаТекста = СтрДлина(Текст);
СчетчикПереносов = 0;
// Подсчитываем количество символов перевода строки (ПС)
Для СимволНомер = 1 По СтрДлинаТекста Цикл
Если Сред(Текст, СимволНомер, 1) = Символы.ПС Тогда
СчетчикПереносов = СчетчикПереносов + 1;
КонецЕсли;
КонецЦикла;
// Динамически управляем высотой элемента на клиенте
НоваяВысота = СчетчикПереносов + 1;
Если Элементы.Реквизит1.Высота <> НоваяВысота Тогда
Элементы.Реквизит1.Высота = НоваяВысота;
КонецЕсли;
КонецПроцедуры
Благодаря использованию метода ПодключитьОбработчикОжидания, само событие ИзменениеТекстаРедактирования отрабатывает мгновенно, не вызывая подвисаний интерфейса и не конфликтуя с платформенными механизмами обновления данных.
Несмотря на кажущиеся сложности, это событие незаменимо во многих интерфейсных решениях. Рассмотрим несколько реальных и полезных сценариев, которые мы можем внедрить в свои конфигурации.
Представим форму, где пользователь выбирает контрагента, а ниже отображается список его договоров. Если пользователь начинает стирать или изменять имя контрагента в поле ввода, старый список договоров на форме становится неактуальным и вводит в заблуждение. Мы можем превентивно очищать или скрывать связанные списки, как только началось редактирование.
Рассмотрим пример кода:
&НаКлиенте
Процедура КонтрагентИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
// Если пользователь начал стирать или менять имя, оперативно убираем подсказки
Элемент.ПодсказкаВвода = "Выберите контрагента из списка...";
// Отключаем видимость неактуального динамического списка договоров
// Чтобы избежать серверного вызова, используем установку отбора без обращения к БД
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
СписокДоговоров,
"Выводить",
Ложь,
ВидСравненияКомпоновкиДанных.Равно,
,
Истина
);
КонецПроцедуры
Очень удобный сценарий для текстовых полей (например, «Комментарий» или «Содержание»). Когда пользователь активирует пустое поле и вводит первый символ, мы можем сразу открыть ему список предопределенных шаблонов или популярных фраз, чтобы ускорить заполнение формы.
Проанализируем пример такой реализации:
&НаКлиенте
Процедура КомментарийИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
// Если это первый введенный символ в пустое поле
Если СтрДлина(СокрЛП(Текст)) = 1 Тогда
// Отменяем стандартный автоподбор платформы
СтандартнаяОбработка = Ложь;
// Открываем форму выбора шаблонов сообщений
ПараметрыВыбора = Новый Структура("РежимВыбора, ТекстПоиска", Истина, Текст);
ОткрытьФорму("Справочник.ШаблоныСообщений.ФормаВыбора", ПараметрыВыбора, Элементы.Комментарий);
КонецЕсли;
КонецПроцедуры
В некоторых задачах требуется, чтобы вводимый текст (например, артикул, VIN-код автомобиля или серия паспорта) всегда состоял из заглавных букв латиницы или кириллицы. Мы можем на лету переводить вводимые символы в верхний регистр. Для этого обязательно нужно установить свойство ОбновлениеТекстаРедактирования в значение Не использовать.
&НаКлиенте
Процедура КодМашиныИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
// Преобразуем набранный текст к верхнему регистру
ТекстВерхнийРегистр = ВРег(Текст);
// Если текст изменился, заменяем его в поле ввода
Если Текст <> ТекстВерхнийРегистр Тогда
Текст = ТекстВерхнийРегистр;
КонецЕсли;
КонецПроцедуры
Подводя итог, сформулируем основные правила работы с событием ИзменениеТекстаРедактирования, которые уберегут вас от ошибок и нестабильного поведения интерфейса:
ОбновлениеТекстаРедактирования в положение Не использовать.&НаСервере) внутри этого обработчика. Если запрос к базе данных жизненно необходим, делегируйте его выполнение обработчику ожидания через ПодключитьОбработчикОжидания.Соблюдение этих простых принципов превратит работу с текстовыми полями в управляемых формах 1С в отзывчивый, удобный и стабильный инструмент для конечных пользователей.