Как правильно программно обновить динамический список в 1С?

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

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

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

Выясняем причину: почему обычное обновление «зависает»?

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

Когда мы вызываем стандартный метод обновления динамического списка:


&НаКлиенте
Процедура КомандаОбновить(Команда)
    Элементы.Список.Обновить();
КонецПроцедуры

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

  1. Форма открыта в 12:00:00. Параметру Период передано значение 12:00:00.
  2. В 12:01:00 пользователь создает и проводит новый документ установки цен. Время документа — 12:01:00.
  3. В 12:02:00 пользователь нажимает кнопку обновления. Список отправляет запрос в СУБД с параметром Период = 12:00:00. Новая цена, созданная в 12:01:00, просто отсекается фильтром по времени и не попадает в выборку.
  4. При удалении старого документа (созданного, например, вчера) данные обновляются корректно, так как изменение происходит внутри временного интервала «до 12:00:00».

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

Решение №1: Динамическая перезапись параметров списка

Самый простой и эффективный способ решить проблему — принудительно обновлять параметр Период перед каждым вызовом метода Обновить(). Мы берем текущую дату на клиенте и передаем ее в параметры списка.

Рассмотрим пример кода, который решает эту задачу:


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

Если обновление требуется выполнять из контекста серверных процедур, то код будет выглядеть немного иначе. Мы разделяем логику на серверную установку параметров и клиентское визуальное обновление:


&НаСервере
Процедура ОбновитьПериодНаСервере()
    // Метод установки параметров доступен на сервере напрямую из объекта Список
    Список.Параметры.УстановитьЗначениеПараметра("Период", ТекущаяДата());
КонецПроцедуры

&НаКлиенте
Процедура КомандаОбновитьСерверная(Команда)
    ОбновитьПериодНаСервере();
    Элементы.Список.Обновить();
КонецПроцедуры

Полезный совет: Чтобы избежать проблем с документами, которые могут быть записаны «будущим временем» в пределах текущих суток, вместо ТекущаяДата() целесообразно использовать функцию КонецДня(ТекущаяДата()). Это гарантирует, что все операции за сегодня гарантированно попадут в динамический выбор.

Решение №2: Отказ от использования параметра «Период» в запросе

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

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

Важное предупреждение по производительности: Запросы к виртуальным таблицам среза последних без указания конкретного периода могут выполняться медленнее на высоконагруженных базах данных или больших таблицах. СУБД сложнее оптимизировать план запроса, когда дата не зафиксирована константой.

Решение №3: Использование свойства «Основная таблица» и оповещений

Платформа 1С обладает встроенным механизмом отслеживания изменений в базе данных. Если в свойствах вашего динамического списка заполнено поле Основная таблица (например, указано Справочник.Номенклатура или РегистрСведений.ЦеныНоменклатуры), система автоматически рассылает уведомления всем открытым формам при записи или удалении элементов этой таблицы.

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

  1. В форме объекта (например, документа «Установка цен номенклатуры»), который создает новые записи, в обработчике события ПослеЗаписи вызываем глобальный метод оповещения:
    
    &НаКлиенте
    Процедура ПослеЗаписи(ПараметрыЗаписи)
        Оповестить("Запись_УстановкаЦенНоменклатуры", ПараметрыЗаписи, Объект.Ссылка);
    КонецПроцедуры
    
  2. В нашей форме с динамическим списком (внешней обработке) определяем обработчик события ОбработкаОповещения:
    
    &НаКлиенте
    Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
        // Проверяем, что событие относится к нужному нам документу
        Если ИмяСобытия = "Запись_УстановкаЦенНоменклатуры" Тогда
            // Актуализируем параметры запроса
            Список.Параметры.УстановитьЗначениеПараметра("Период", ТекущаяДата());
            // Обновляем список на экране пользователя
            Элементы.Список.Обновить();
        КонецЕсли;
    КонецПроцедуры
    

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

Разберем разницу: Обновить() против ОбновитьОтображениеДанных()

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

Резюме

Для надежного обновления динамических списков со сложной структурой запросов и виртуальными таблицами среза последних всегда сочетайте актуализацию параметров выборки и вызов метода принудительного обновления. Оптимальным выбором по соотношению производительности и автоматизации является интеграция через обработчики ОбработкаОповещения на управляемой форме.

← На главную