Разработка и Конфигурация · 14 мин
Как обновлять динамический список в 1С
Как обновлять динамический список в 1С: метод Обновить(), автоматическое обновление, события формы, обновление из кода и типичные ошибки разработчиков.
Динамический список — основной инструмент отображения табличных данных в управляемых формах 1С. Он строится на запросе и сам управляет выборкой, но его данные не всегда актуальны в момент, когда это нужно пользователю. Записали новый документ, изменили справочник в фоновом задании, провели обмен данными — список на экране может показывать устаревшую информацию. Задача разработчика — правильно организовать обновление: вручную по кнопке, автоматически по таймеру или принудительно из кода.
Способов несколько, и у каждого свои ограничения. Метод Обновить() работает только для реквизитов формы типа «ДинамическийСписок». Автоматическое обновление удобно, но нагружает сервер при больших таблицах. Оповещения между формами требуют аккуратной подписки на события. Ниже разобраны все рабочие варианты с примерами кода, условиями выбора и проверкой результата.
Что такое динамический список и когда он устаревает
Динамический список — реквизит формы, который отображает результат запроса к базе данных: таблицы справочников, документов, регистров сведений и накопления. Платформа вычитывает данные порциями по мере прокрутки, поэтому список работает быстро даже на больших таблицах. Платой за это является то, что уже считанные строки не перечитываются сами по себе.
Типичные ситуации, когда список на экране расходится с реальными данными: пользователь записал документ в соседнем окне, регламентное задание обновило регистр, обмен загрузил новые объекты, другой пользователь пометил записи на удаление. Во всех этих случаях данные в базе изменились, а отображение осталось прежним до явного обновления.
Стандартные формы списков, которые платформа генерирует автоматически, частично решают проблему сами: при записи объекта из формы этого же списка данные обновляются штатно. Проблемы начинаются в самописных формах, при изменениях из других окон и при фоновых механизмах — тут обновление нужно организовать вручную.
Программное обновление через метод Обновить()
Самый прямой способ — вызвать метод Обновить() у элемента формы, связанного с динамическим списком. Метод доступен в клиентском контексте и заставляет платформу перечитать данные с учётом текущих отборов и сортировок:
&НаКлиенте
Процедура ОбновитьСписок(Команда)
Элементы.СписокДокументов.Обновить();
КонецПроцедурыЕсли нужно обновить список из серверной процедуры, вызывайте метод у реквизита формы, а не у элемента:
&НаСервере
Процедура ОбновитьДанныеНаСервере()
ЭтаФорма.СписокДокументов.Обновить();
КонецПроцедурыВажный нюанс: вызов Обновить() у реквизита на сервере сработает, но результат доедет до клиента только после завершения серверного вызова. Если обновление нужно именно по действию пользователя (кнопка, команда), делайте вызов на клиенте — так вы избежите лишнего обращения к серверу и получите немедленную реакцию интерфейса.
Проверить результат просто: после вызова метода новые записи появляются в списке, удалённые исчезают, а текущая позиция курсора по возможности сохраняется на той же строке. Если курсор «слетает» на первую строку, чаще всего дело в изменившемся отборе или сортировке, а не в самом обновлении.
Автоматическое обновление по таймеру
Когда список должен актуализироваться без участия пользователя — например, монитор очереди заказов или рабочий стол кладовщика — есть два подхода: штатное автообновление и обработчик ожидания.
Штатный механизм настраивается в свойствах динамического списка в конфигураторе: установите свойство Автообновление в «Истина» и задайте ПериодАвтообновления в секундах. Платформа будет сама перечитывать данные через указанный интервал. Способ не требует кода, но применим не ко всякой форме и не всегда доступен для произвольных запросов.
Второй вариант — обработчик ожидания на клиенте. Он универсальнее и позволяет дополнительно проверять условия перед обновлением:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ПодключитьОбработчикОжидания("ОбновитьСписокПоТаймеру", 60);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьСписокПоТаймеру()
Элементы.СписокДокументов.Обновить();
КонецПроцедурыОтключение обработчика при закрытии формы
Подключённый обработчик ожидания живёт, пока жива форма, но при закрытии его стоит отключить явно — это защищает от вызовов процедуры в уже разрушенном контексте при нестандартных сценариях переиспользования формы:
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
ОтключитьОбработчикОжидания("ОбновитьСписокПоТаймеру");
КонецПроцедурыОбновление через оповещения между формами
Частый сценарий: из формы списка открывается форма объекта, пользователь записывает объект, и список должен отразить изменение. Платформа умеет делать это автоматически для стандартных форм, но в произвольных формах надёжнее использовать явные оповещения.
После записи объекта вызовите глобальное оповещение об изменении:
&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
ОповеститьОбИзменении(Объект.Ссылка);
КонецПроцедурыМетод ОповеститьОбИзменении() заставляет платформу обновить все открытые динамические списки, в которых отображается этот объект, а также связанные с ним элементы управления. Это штатный механизм, и он предпочтительнее ручного перебора открытых окон.
Если нужно обновить конкретную форму списка с дополнительной логикой, используйте пару Оповестить() и обработчик ОбработкаОповещения():
// В форме, где произошло изменение:
Оповестить("ИзмененыДанныеЗаказов", ПараметрыИзменения, ЭтаФорма);
// В форме со списком:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ИзмененыДанныеЗаказов" Тогда
Элементы.СписокДокументов.Обновить();
КонецЕсли;
КонецПроцедуры- 1В форме-источнике после записи вызовите ОповеститьОбИзменении(Ссылка) или Оповестить() с уникальным именем события
- 2В форме со списком добавьте обработчик ОбработкаОповещения и проверьте имя события
- 3Внутри обработчика вызовите Элементы.ИмяСписка.Обновить()
- 4Откройте обе формы, измените объект и убедитесь, что список обновился без переоткрытия
Обновление после фоновых заданий и обмена данными
Сложнее всего с изменениями, которые происходят вне клиентского сеанса: регламентные задания, фоновая загрузка, обмен с другими системами. Клиент об этих изменениях не узнает сам — оповещения между сеансами в платформе не работают.
Рабочих варианта два. Первый — тот же обработчик ожидания, который периодически обновляет список независимо от причины изменений. Второй — обновление по событию активации окна: когда пользователь возвращается к форме, список перечитывается:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
// ... другие события
КонецПроцедуры
// Либо в модуле формы через подключение к событию активации приложения
Для массовых загрузок из собственного кода есть лайфхак: после завершения серверной процедуры загрузки верните на клиент признак успеха и вызовите Обновить() один раз, а не после каждой записанной строки. Обновление списка в цикле — одна из самых частых причин «подвисания» форм.
Управление обновлением при изменении отбора и параметров
При программной установке отбора или параметров запроса динамический список обычно перечитывается автоматически — отдельный вызов Обновить() не требуется. Но если параметры меняются пакетно, платформа может выполнить несколько перечитываний подряд. Чтобы этого избежать, сначала установите все параметры и отборы, а затем при необходимости обновите список один раз:
&НаКлиенте
Процедура УстановитьОтборПоПериоду(Команда)
СписокДокументов.Параметры.УстановитьЗначениеПараметра("НачалоПериода", НачалоМесяца(ТекущаяДата()));
СписокДокументов.Параметры.УстановитьЗначениеПараметра("КонецПериода", КонецМесяца(ТекущаяДата()));
Элементы.СписокДокументов.Обновить();
КонецПроцедурыЕсли список использует произвольный запрос с собственной таблицей значений или временными таблицами, помните: динамический список всегда выполняет запрос заново при обновлении. Данные, которые вы поместили во временное хранилище при создании формы, при обновлении не пересчитаются — для таких сценариев нужно заново формировать источник данных на сервере.
Выбор способа обновления под задачу
Единого «правильного» способа нет — выбор зависит от источника изменений и требований к актуальности. Ниже сопоставлены основные варианты.
Способы обновления динамического списка
Подходит, когда актуальность нужна по требованию пользователя. Минимальная нагрузка, но человек может забыть обновить
Оптимально при изменениях из форм того же сеанса. Штатный механизм, не требует таймеров, но не работает между сеансами
Для мониторов и данных, меняющихся фоновыми заданиями. Универсально, но создаёт постоянную фоновую нагрузку
Самый простой вариант без кода. Подходит для типовых форм списков, но менее гибок по условиям
Для массовых загрузок из собственного кода: один вызов Обновить() после завершения всей операции
Как выбрать действие
Проверка результата и диагностика проблем
После внедрения обновления проверьте поведение в реальных сценариях: откройте две формы, измените данные, дождитесь срабатывания механизма. Список должен показать актуальные строки без мерцания, потери позиции курсора и заметной паузы.
Как проверить результат
Записанный в другой форме объект появляется в списке после срабатывания механизма
Запись видна только после закрытия и повторного открытия формы
После обновления текущая строка сохраняется
Курсор сбрасывается на первую строку при каждом обновлении
Обновление занимает доли секунды и не блокирует интерфейс
Форма подвисает, особенно при автообновлении
Запросы выполняются только по событию или с разумным интервалом
Запросы идут непрерывно, в консоли СУБД видны повторяющиеся обращения
Если обновление не срабатывает, проверьте по порядку: правильно ли указано имя элемента формы (а не реквизита), в каком контексте вызван метод, не переопределён ли текст запроса списка так, что новые записи не проходят отбор, и не фильтрует ли установленный отбор именно те данные, которые вы ожидаете увидеть. Чаще всего «не обновляется список» на деле означает «запись не проходит отбор».
Перед тем как подключать таймер автообновления, проверьте, нельзя ли обойтись оповещениями. В большинстве форм списков изменения приходят из действий самих пользователей, и ОповеститьОбИзменении() закрывает задачу без постоянной нагрузки на сервер. Таймер оправдан только для мониторов и данных из фоновых процессов.
Что важно запомнить
Динамический список обновляется методом Обновить() у элемента формы (на клиенте) или реквизита (на сервере). Для изменений из других форм сеанса используйте ОповеститьОбИзменении(), для фоновых процессов — обработчик ожидания с разумным интервалом. При массовых операциях обновляйте список один раз в конце, а при смене параметров — сначала установите их все, затем обновите. Избегайте частых таймеров на больших таблицах.
Частые вопросы
Почему Обновить() не срабатывает из серверной процедуры?
Скорее всего, вы вызываете метод у элемента формы (Элементы.Список) в безконтекстной серверной процедуре — там элементы недоступны. Используйте реквизит формы: ЭтаФорма.ИмяСписка.Обновить(). Если процедура вызывается с клиента, результат доедет до интерфейса после завершения серверного вызова; для мгновенной реакции вызывайте обновление на клиенте.
Можно ли обновить список в сеансе другого пользователя?
Напрямую — нет. Оповещения и ОповеститьОбИзменении() работают только внутри текущего сеанса. Чтобы другие пользователи увидели изменения, им нужно либо обновить список вручную, либо использовать автообновление по таймеру, либо обновление при активации окна.
Курсор сбрасывается на первую строку после обновления — что делать?
Так происходит, когда после обновления платформа не находит прежнюю текущую строку: запись удалена, не проходит новый отбор или изменилась сортировка. Если запись на месте, но позиция теряется, проверьте, не меняете ли вы программно отбор или параметры в момент обновления — каждая смена отбора переустанавливает выборку.
Какой интервал автообновления считать безопасным?
Универсального значения нет — оно зависит от объёма таблицы, сложности запроса и числа пользователей с открытой формой. На практике интервалы меньше 30 секунд для списков с соединениями и отборами уже создают ощутимую фоновую нагрузку. Начните с 60 секунд и уменьшайте, только контролируя время выполнения запроса списка.
Нужно ли вызывать Обновить() после программной установки отбора?
Обычно нет — изменение отбора, параметров или сортировки динамического списка само инициирует перечитывание данных. Явный вызов Обновить() после этого приведёт к повторному запросу. Исключение — случаи, когда вы меняли данные внешними механизмами и хотите гарантированно перечитать результат.
Как обновить список, если он построен на произвольном запросе?
Тем же методом Обновить() — платформа заново выполнит произвольный запрос. Но убедитесь, что все параметры запроса актуальны на момент обновления: если запрос использует параметры-таблицы или значения, установленные при создании формы, их нужно переустановить перед вызовом, иначе список покажет устаревший или пустой результат.