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