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