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