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