Как избавиться от лишнего клика (потери фокуса) при изменении реквизита в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на управляемых формах 1С мы периодически сталкиваемся с неприятной особенностью: после ввода данных в поле и попытке кликнуть мышкой на следующий элемент управления, фокус не переходит с первого раза. Требуется сделать «лишний клик», чтобы активировать нужное поле ввода. При этом, если заканчивать ввод нажатием клавиши Enter, переход на следующий элемент отрабатывает корректно и мгновенно. Давайте разберем эту ситуацию по шагам и выясним причину такого поведения системы, а также рассмотрим рабочие способы решения данной проблемы.

Проанализируем ситуацию и выясним причину

Чаще всего подобная проблема возникает при работе с программно генерируемыми полями ввода или выбора, для которых назначен обработчик события ПриИзменении. Экспериментальным путем легко выяснить, что сбой фокуса происходит из-за вызова процедур с директивой &НаСервере внутри обработчика изменения. Даже если серверная процедура абсолютно пустая, сам факт контекстного вызова ломает естественный пользовательский поток.

Техническая причина кроется в механизмах отрисовки и обновления интерфейса платформы (особенно ярко это начало проявляться с релизов 8.3.14 - 8.3.15). Когда из события ПриИзменении вызывается контекстная серверная процедура, платформа 1С собирает все данные формы, отправляет их на сервер, а по возвращении на клиент полностью перерисовывает (обновляет) состояние элементов формы. В этот микромомент прерывается UI-поток: система просто игнорирует клик пользователя по другому полю, так как форма была принудительно обновлена.

Основное решение: отказ от контекстного вызова

Рассмотрим подробнее самый правильный и архитектурно верный способ исправления этой ошибки. Нам необходимо избавиться от полной передачи контекста формы на сервер при каждом изменении реквизита.

Для этого процедуру, которая обрабатывает изменение данных, нужно вызывать не с директивой &НаСервере, а с директивой &НаСервереБезКонтекста. При вызове внеконтекстной процедуры платформа не гоняет весь объем данных формы на сервер и обратно. Следовательно, жесткого обновления формы не происходит, и клиент 1С нормально завершает действие мыши — фокус переходит куда нужно с первого раза.

Важное архитектурное правило: В идеальном коде 1С с директивой &НаСервере должны определяться только предопределенные обработчики событий самой формы (например, ПриСозданииНаСервере). Все остальные серверные вызовы, особенно из событий элементов, желательно делать внеконтекстными, передавая в них только нужные параметры.

Пример правильного вызова:


&НаКлиенте
Процедура ДинамическоеПолеПриИзменении(Элемент)
    
    // Получаем необходимые данные из текущих элементов
    ТекущееЗначение = ЭтаФорма.ДанныеПоля;
    
    // Вызываем внеконтекстную процедуру, передавая только то, что нужно
    Результат = ОбработатьИзменениеНаСервереБезКонтекста(ТекущееЗначение);
    
    // Обновляем данные на клиенте
    ЭтаФорма.РезультатПоля = Результат;

КонецПроцедуры

&НаСервереБезКонтекста
Функция ОбработатьИзменениеНаСервереБезКонтекста(Значение)
    
    // Выполняем логику без тяжелого контекста формы
    Возврат Значение * 2; // Условная логика

КонецФункции

Да, переход на &НаСервереБезКонтекста может потребовать серьезного пересмотра логики (особенно если в обработке задействованы таблицы значений или деревья), но это гарантированно решит проблему с фокусом и ускорит работу формы в целом.

Альтернативные пути обхода проблемы

Посмотрим на примеры, когда переписать логику под внеконтекстный вызов слишком сложно или трудозатратно (например, если нужно плотно работать с множеством динамических реквизитов всей формы сразу). В таких случаях мы можем применить обходные маневры.

  1. Использование обработчика ожидания:
    В событии ПриИзменении на клиенте мы не вызываем серверный код напрямую. Вместо этого мы используем метод ПодключитьОбработчикОжидания с минимальной задержкой (например, 0.1 секунды). Это позволяет платформе сначала корректно отработать клик пользователя, перевести фокус, а уже через мгновение асинхронно выполнить серверный код.
    
    &НаКлиенте
    Процедура РеквизитПриИзменении(Элемент)
        ПодключитьОбработчикОжидания("ОтложеннаяОбработкаИзменения", 0.1, Истина);
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ОтложеннаяОбработкаИзменения()
        ОбработкаИзмененияНаСервере();
    КонецПроцедуры
    
  2. Принудительный возврат фокуса:
    Если мы заранее знаем бизнес-логику заполнения полей, мы можем программно перевести фокус на следующий элемент после возврата с сервера. Для этого используется свойство ТекущийЭлемент.
    
    &НаКлиенте
    Процедура Поле1ПриИзменении(Элемент)
        ВыполнитьТяжелыйКодНаСервере();
        ЭтаФорма.ТекущийЭлемент = Элементы.Поле2; // Принудительно ставим фокус
    КонецПроцедуры
    
  3. Настройка свойства элемента:
    В некоторых сценариях помогает изменение свойства поля ввода при его создании. Использование свойства ОбновлениеТекстаРедактирования со значением ОбновлениеТекстаРедактирования.ПриИзмененииЗначения иногда предотвращает агрессивный сброс состояния элемента при обновлении формы. Установить это свойство можно как в конфигураторе, так и программно при генерации элемента.

Подводя итог: если вы столкнулись с проблемой лишнего клика, в первую очередь постарайтесь оптимизировать код, заменив вызовы &НаСервере на &НаСервереБезКонтекста. Это не только исправит досадный баг интерфейса, но и сделает ваше приложение более быстрым и отзывчивым для пользователей.

← На главную