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