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