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