При разработке прикладных решений на платформе 1С:Предприятие 8.3 часто возникает задача: пользователь открыл форму обработки или журнала с динамическим списком, а в это время на сервере (в подписке на событие, фоновом задании или при работе другого сеанса) происходит запись регистров или справочников. Рассмотрим, как организовать автоматическое обновление данных в динамическом списке и какие ограничения платформы необходимо учитывать.
Проанализируем ключевое архитектурное ограничение платформы: стандартные методы клиентского оповещения Оповестить и ОповеститьОбИзменении доступны исключительно в контексте тонкого, толстого и веб-клиента. Вызвать их напрямую из серверных процедур (в модулях объектов, общих модулях с признаком «Сервер» или в обработчиках подписок на события) невозможно.
Разберем основные варианты решения этой задачи в зависимости от сценария работы и версии платформы.
Посмотрим на самый простой вариант, не требующий написания серверного кода оповещения — настройку свойств динамического списка. В управляемой форме для реквизита типа ДинамическийСписок можно включить периодический опрос базы данных.
Для настройки выполним следующие шаги:
Истина.Также эти параметры можно задать программно при создании формы на сервере или при открытии:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Список.Автообновление = Истина;
Список.ПериодАвтообновления = 10; // интервал обновления в секундах
КонецПроцедуры
Важно: частый опрос базы данных тяжелыми запросами динамического списка может создавать существенную нагрузку на СУБД. Рекомендуется использовать данный механизм с разумным интервалом или при небольшом количестве одновременно работающих пользователей.
Если запись данных в подписке на событие инициирована действием из текущего сеанса пользователя (например, при нажатии кнопки в обработке), то после возврата управления на клиент можно выполнить принудительное оповещение или обновление таблицы формы.
Разберем пример клиентского кода:
&НаКлиенте
Процедура ВыполнитьОбработкуИОбновить(Команда)
// Вызов серверной процедуры, где срабатывает подписка на событие
ВыполнитьЗаписьДанныхНаСервере();
// Вариант 1: Оповещение об изменении конкретной ссылки или ключа записи
ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура"));
// Вариант 2: Прямое принудительное обновление динамического списка
Элементы.Список.Обновить();
КонецПроцедуры
Выясним причину, почему метод ОповеститьОбИзменении может не обновить данные: если в динамическом списке используется сложный произвольный запрос с соединениями, автоматическое обновление срабатывает только для основной таблицы списка. Если модифицировались соединенные таблицы, необходимо использовать прямой вызов метода Элементы.ИмяТаблицы.Обновить().
Если данные изменяются фоновыми заданиями или другими пользователями, но включать тяжелое автообновление динамического списка нежелательно, применим оптимизированный подход с легким флагом модификации.
Рассмотрим по шагам реализацию этого механизма:
ПодключитьОбработчикОжидания.Элементы.Список.Обновить() и запоминаем новую версию.Посмотрим на пример реализации в форме:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ТекущаяВерсияДанных = 0;
ПодключитьОбработчикОжидания("ПроверитьОбновлениеДанных", 5);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьОбновлениеДанных()
АктуальнаяВерсия = ПолучитьАктуальнуюВерсиюНаСервере();
Если АктуальнаяВерсия <> ТекущаяВерсияДанных Тогда
ТекущаяВерсияДанных = АктуальнаяВерсия;
Элементы.Список.Обновить();
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьАктуальнуюВерсиюНаСервере()
// Получение значения легкой константы или записи регистра
Возврат Константы.ВерсияИзмененияДанных.Получить();
КонецФункции
В современных версиях платформы (начиная с 8.3.10) для передачи информации с сервера на клиентские рабочие места используется механизм Системы взаимодействия. Он позволяет отправлять push-сообщения конкретным пользователям прямо из серверного контекста без постоянного периодического опроса базы данных. При получении системного сообщения на клиенте срабатывает обработчик, в котором можно вызвать метод Элементы.Список.Обновить().