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

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

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

Однако здесь разработчиков подстерегает крайне неприятный эффект: в момент срабатывания таймера и обновления данных у пользователя «слетает» активный ввод. Открытые калькуляторы в числовых полях закрываются, выпадающие списки выбора мгновенно сворачиваются, а недописанный текст в полях ввода очищается или выделяется, заставляя пользователя начинать ввод заново. Выясним причину этой проблемы и подробно разберем несколько эффективных способов борьбы с ней.

Почему происходит сброс фокуса и закрытие элементов?

Рассмотрим детально механику взаимодействия клиента и сервера в управляемом приложении. Когда срабатывает подключенный обработчик ожидания (например, через метод ПодключитьОбработчикОжидания с интервалом в 5 секунд), управление передается серверной процедуре. Если эта процедура объявлена с директивой &НаСервере (то есть выполняется в контексте формы), происходит следующее:

  1. Весь контекст управляемой формы (все реквизиты, таблицы, значения) сериализуется на клиенте и передается на сервер.
  2. Сервер обрабатывает данные, обновляет реквизиты (например, перезаполняет таблицу остатков) и отправляет измененный контекст обратно на клиент.
  3. При получении данных клиентская платформа 1С пытается синхронизировать пользовательский интерфейс с новым состоянием контекста. Для этого она инициирует принудительную перерисовку элементов управления.

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

Проанализируем практические подходы к решению этой проблемы — от самых простых настроек интерфейса до глубоких архитектурных изменений.

Решение 1. Использование свойства «ОбновлениеТекстаРедактирования»

Самый быстрый способ локально победить стирание вводимого текста в простых полях (строках, числах, датах) — изменить настройки самого элемента формы. По умолчанию у элементов ввода свойство ОбновлениеТекстаРедактирования установлено в значение Авто.

Если мы заменим его на значение При изменении значения, платформа изменит свое поведение:

Важное ограничение: этот способ отлично защищает от потери набранного текста, но он абсолютно бессилен перед проблемой закрытия калькуляторов, календарей и выпадающих списков автоподбора. Если пользователь открыл калькулятор и в этот момент сработал таймер — окно расчетов все равно закроется.

Решение 2. Перенос данных в Динамический список

Если ваша задача — обновлять таблицу остатков или список документов, использование табличной части или таблицы значений на форме является архитектурной ошибкой. Гораздо более надежный и профессиональный подход — использование объекта ДинамическийСписок.

Рассмотрим, почему динамический список решает проблему:

Для реализации этого метода достаточно заменить реквизит формы типа ТаблицаЗначений на ДинамическийСписок с произвольным запросом к регистру остатков, вывести его на форму и настроить период автообновления.

Решение 3. Вызовы сервера без контекста

Если отказаться от таблицы значений невозможно, мы можем оптимизировать серверные вызовы. Вместо контекстного вызова &НаСервере нам необходимо использовать вызов с директивой &НаСервереБезКонтекста.

При бесконтекстном вызове клиент не передает на сервер состояние всей формы, а сервер не возвращает ее обратно. Следовательно, платформа не перерисовывает элементы формы автоматически, и интерфейс пользователя не «дергается».

Разберем по шагам, как реализовать такое обновление на примере таблицы остатков:


&НаКлиенте
Процедура ОбработчикТиковСекунд()
    
    // Получаем данные с сервера без передачи контекста формы
    НовыеДанныеОстатков = ПолучитьОстаткиНаСервереБезКонтекста();
    
    // Аккуратно обновляем только конкретные строки таблицы на клиенте, 
    // не затрагивая фокус ввода в других полях формы
    ОбновитьТаблицуНаКлиенте(НовыеДанныеОстатков);
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьОстаткиНаСервереБезКонтекста()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
        |   ТоварыНаСкладахОстатки.ВНаличииОстаток КАК Остаток
        |ИЗ
        |   РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки";
        
    ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
    
    // Передаем данные на клиент в виде массива структур, так как ТаблицаЗначений не передается напрямую
    МассивРезультата = Новый Массив;
    Для Каждого Строка Из ТаблицаРезультата Цикл
        СтруктураСтроки = Новый Структура("Номенклатура, Остаток", Строка.Номенклатура, Строка.Остаток);
        МассивРезультата.Добавить(СтруктураСтроки);
    КонецЦикла;
    
    Возврат МассивРезультата;
    
КонецФункции

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

Благодаря такому подходу мы полностью контролируем процесс обновления данных. Изменения затрагивают исключительно коллекцию остатков, а все остальные элементы интерфейса остаются в стабильном состоянии.

Решение 4. Временное отключение таймера при активности пользователя

Если фоновое обновление мешает вводу данных в конкретных «чувствительных» полях, мы можем временно усыплять обработчик ожидания на время работы пользователя с этими полями.

Рассмотрим алгоритм реализации такой блокировки:

  1. При начале редактирования поля ввода или при открытии калькулятора мы отключаем фоновый таймер.
  2. После того как пользователь завершил ввод и нажал Enter (или перевел фокус на другой элемент), мы снова запускаем таймер.

Посмотрим на пример кода, реализующий эту логику для числового поля ввода:


&НаКлиенте
Процедура ЧувствительноеПолеНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    // Пользователь нажал на кнопку выбора (например, открывает калькулятор)
    // Временно отключаем обновление, чтобы калькулятор не закрылся
    ОтключитьОбработчикОжидания("ОбработчикТиковСекунд");
КонецПроцедуры

&НаКлиенте
Процедура ЧувствительноеПолеПриИзменении(Элемент)
    // Ввод успешно завершен, данные сохранены в реквизит.
    // Снова включаем фоновое обновление формы
    ПодключитьОбработчикОжидания("ОбработчикТиковСекунд", 5);
КонецПроцедуры

&НаКлиенте
Процедура ЧувствительноеПолеОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, СтандартнаяОбработка)
    // Дополнительная подстраховка на случай, если пользователь просто закончил ввод текста
    ПодключитьОбработчикОжидания("ОбработчикТиковСекунд", 5);
КонецПроцедуры

Этот способ требует написания дополнительного кода для обработчиков событий элементов формы, но гарантирует абсолютный комфорт для пользователя при заполнении важных документов.

Решение 5. Событийное обновление через Систему взаимодействия

Постоянный опрос сервера каждые 5 секунд (пулинг) создает огромную паразитную нагрузку на СУБД и рабочие процессы 1С. Если форму откроют одновременно 50 пользователей, сервер будет непрерывно занят обработкой бессмысленных запросов, большая часть которых вернет те же самые данные.

Современное и наиболее технологичное решение — переход от постоянного опроса по таймеру к архитектуре получения уведомлений (push-уведомления) через встроенную в 1С Систему взаимодействия.

Принцип работы выглядит следующим образом:

Это полностью избавляет систему от холостых запросов каждые 5 секунд, снижает нагрузку на сервер до нуля в периоды отсутствия транзакций и гарантирует актуальность данных без ущерба для удобства работы пользователя.

← На главную