При разработке управляемых форм в 1С:Предприятие программисты часто сталкиваются с неочевидным поведением фокуса ввода. Типичный сценарий: пользователь вводит текстовые данные в поле ввода, а затем сразу же (не нажимая клавишу Enter или Tab и не переходя в другое полноценное текстовое поле) кликает на декорацию-надпись, оформленную в виде гиперссылки. Логично ожидать, что платформа зафиксирует изменение данных в исходном поле ввода и вызовет назначенный обработчик события ПриИзменении. Однако на практике этого не происходит: событие попросту игнорируется, а курсор визуально может оставаться в отредактированном поле.
Давайте разберем по шагам, почему так происходит, как на это влияет режим совместимости конфигурации и какие практические способы существуют для преодоления этой архитектурной особенности платформы.
Для того чтобы выяснить первопричину такого поведения, обратимся к особенностям работы фокуса ввода, которые были официально задокументированы фирмой «1С» (начиная с версии платформы 8.3.9 в разделе «Особенности поведения системы в различных режимах»). Поведение системы напрямую зависит от установленного в свойствах конфигурации режима совместимости.
Рассмотрим два основных сценария работы платформы:
В тонком и толстом клиентах при клике на декорацию-гиперссылку вызывается ее обработчик нажатия (или событие ОбработкаНавигационнойСсылки), но все изменения в редактируемом поле ввода принудительно откатываются к первоначальному значению, которое было до начала ввода текста. При этом событие ПриИзменении вообще не срабатывает.
В веб-клиенте обработчик ссылки срабатывает, в поле ввода отображается новое значение, но событие ПриИзменении все равно не инициируется.
В этом режиме событие ПриИзменении должно отрабатывать штатно, фиксируя изменения в поле ввода. Но здесь кроется важный технический нюанс: это происходит гарантированно только в том случае, если в обработчике нажатия гиперссылки (декорации) выполняется контекстный серверный вызов (процедура с директивой &НаСервере). Если обработчик клика по ссылке выполняется исключительно на стороне клиента (&НаКлиенте), то с точки зрения платформы полноценного переключения фокуса не происходит. Фокус «застревает» на поле ввода, и событие ПриИзменении не вызывается.
Ниже подробно разберем четыре практических способа решения этой проблемы.
Проанализируем решение, которое успешно применил автор темы на форуме. Самым быстрым способом заставить платформу зафиксировать изменения в поле ввода является принудительная смена фокуса (текущего элемента формы) в коде обработчика нажатия декорации-гиперссылки.
Посмотрим на пример реализации такого обработчика:
&НаКлиенте
Процедура ИмяГиперссылкиНажатие(Элемент)
// Принудительно переносим фокус на саму декорацию или другой элемент формы,
// чтобы инициировать запись изменений в предыдущем поле ввода
ЭтаФорма.ТекущийЭлемент = Элементы.ДекорацияГиперссылка;
// Выполняем основную логику нашей гиперссылки
ОткрытьИнформационноеОкно();
КонецПроцедуры
При таком подходе в момент присвоения свойству ТекущийЭлемент нового значения платформа понимает, что активный элемент изменился. Она мгновенно завершает редактирование предыдущего поля ввода, вызывает для него событие ПриИзменении, и только после этого продолжает выполнение кода обработчика клика.
Если вы не хотите вручную управлять свойством ТекущийЭлемент, можно использовать встроенный механизм синхронизации платформы. Как мы выяснили ранее, событие ПриИзменении гарантированно отрабатывает, если клиент обращается к серверу за контекстом. Мы можем добавить вызов контекстной серверной процедуры в обработчик клика по гиперссылке.
Разберем этот вариант на примере кода:
&НаКлиенте
Процедура ИмяГиперссылкиНажатие(Элемент)
// Вызываем пустую серверную процедуру для принудительной синхронизации данных
СинхронизироватьДанныеФормыНаСервере();
// Выполняем клиентский код
ОткрытьСтраницуВБраузере();
КонецПроцедуры
&НаСервере
Процедура СинхронизироватьДанныеФормыНаСервере()
// Данная процедура может оставаться пустой.
// Сам факт вызова сервера заставляет платформу передать измененные данные
// из поля ввода на сервер, предварительно вызвав событие "ПриИзменении".
КонецПроцедуры
Этот способ крайне надежен, однако следует помнить, что каждый серверный вызов создает дополнительную нагрузку на сеть и сервер приложений. Используйте его осмотрительно, особенно в высоконагруженных системах или при работе через медленное интернет-соединение.
Наиболее красивым и правильным с точки зрения проектирования интерфейсов решением является замена элемента типа «Декорация» на стандартную кнопку формы. Дело в том, что обычная декорация-надпись на уровне платформы не предназначена для полноценного управления фокусом ввода, в то время как кнопка спроектирована специально для этого.
Давайте настроим этот элемент по шагам:
ПерейтиПоСсылке) и создайте для нее обработчик действия.Поскольку кнопка является интерактивным элементом управления, при клике на нее платформа автоматически и без дополнительных ухищрений забирает фокус из редактируемого поля ввода. В результате событие ПриИзменении отрабатывает абсолютно штатно, а вам не придется писать дополнительные обходные пути в программном коде.
Если вы сопровождаете старую или сильно доработанную конфигурацию, обязательно проверьте свойства самого корня конфигурации. Найдите свойство Режим совместимости. Если там установлено значение 8.3.8 или ниже, настоятельно рекомендуется рассмотреть возможность обновления этого режима до актуальной версии платформы (например, до версии вашей текущей рабочей платформы без совместимости).
Переход на более современные режимы совместимости не только решает проблемы с передачей фокуса, но и открывает доступ к множеству оптимизаций, новым механизмам работы с интерфейсом управляемых форм и повышает общую стабильность системы.
Подводя итог, отметим: если вы столкнулись с тем, что в 1С не срабатывает событие ПриИзменении при клике на декоративную ссылку, лучшим решением будет использование кнопки со стилем гиперссылки (Способ 3). Если же по каким-то причинам интерфейс формы менять нельзя или вы ограничены рамками типовой конфигурации, используйте принудительную установку свойства ТекущийЭлемент (Способ 1) непосредственно в коде обработчика нажатия.