При работе с управляемыми формами в 1С:Предприятии, особенно в режиме "Такси", мы можем столкнуться с ситуацией, когда данные, отображаемые на форме, не соответствуют актуальным значениям в базе данных. Это особенно характерно для реквизитов ссылочного типа, чьи свойства выведены на форму. Давайте подробно разберем эту проблему и найдем эффективное решение.
Представим, что у нас есть внешняя обработка с табличной частью, например, "Номенклатура". В этой табличной части имеется реквизит РесурснаяСпецификация, который ссылается на справочник СправочникСсылка.РесурсныеСпецификации. У этого справочника есть свои реквизиты, такие как НачалоДействия и КонецДействия, которые мы вынесли прямо на форму обработки в виде колонок табличной части.
Ситуация, с которой мы можем столкнуться, следующая: при первоначальном заполнении табличной части формы 1С запоминает значения реквизитов НачалоДействия и КонецДействия для каждой РесурснойСпецификации. Если позже эти реквизиты будут изменены непосредственно в базе данных (например, через другую форму, программно или вручную), то на нашей форме обработки эти изменения никак не отразятся. Более того, мы можем обнаружить, что даже переоткрытие обработки или повторное заполнение табличной части не приводит к актуализации данных. Форма упорно продолжает показывать старые, кэшированные значения.
Это происходит потому, что платформа 1С использует многоуровневое кэширование для оптимизации производительности. Кэш, относящийся к конкретной форме, сбрасывается только при ее полном закрытии или при явном указании системе, что связанные объекты были изменены. Когда мы отображаем реквизиты ссылочного объекта (например, РесурснаяСпецификация.КонецДействия), форма кэширует не только ссылку на объект, но и представление его данных. Если сам объект РесурснаяСпецификация изменяется, форма не всегда автоматически понимает, что нужно обновить его отображаемые свойства.
Многие разработчики, столкнувшись с такой проблемой, в первую очередь пробуют стандартные методы обновления отображения данных. Давайте рассмотрим, какие из них обычно не помогают в данном сценарии:
ЭтаФорма.ОбновитьОтображениеДанных(): Этот метод обновляет содержимое элементов управления формы, но он ориентирован в первую очередь на реквизиты самого объекта формы или на элементы, связанные с ее основным объектом. В нашем случае, когда проблема касается свойств ссылочного объекта, выведенных на форму, этот метод часто оказывается бессильным.ЭтаФорма.ОбновитьОтображениеДанных(Элементы.ИмяЭлемента): Попытка указать конкретный элемент (например, табличную часть Номенклатура или даже отдельную колонку НоменклатураРесурснаяСпецификацияКонецДействия) также не приносит желаемого результата. Система обновляет отображение, но берет данные из того же кэша, который содержит устаревшие значения для свойств ссылочного объекта.Элементы.ИмяЭлемента.Обновить(): Для табличных частей, представленных динамическими списками, метод Обновить() заставляет список перечитать свои данные. Однако в нашем случае табличная часть является реквизитом формы, а не динамическим списком. И даже если бы это был динамический список, проблема кэширования свойств вложенного объекта могла бы остаться.Как мы видим из обсуждения на форуме, эти подходы были опробованы и не привели к решению:
&НаКлиенте
Процедура ОбновитьТаблицу(Команда)
ЭтаФорма.ОбновитьОтображениеДанных(); // не помогает
ЭтаФорма.ОбновитьОтображениеДанных(Элементы.Номенклатура); // не помогает
ЭтаФорма.ОбновитьОтображениеДанных(Элементы.НоменклатураРесурснаяСпецификацияКонецДействия); // не помогает
Элементы.Номенклатура.Обновить(); // не помогает
КонецПроцедуры
Ключевая проблема здесь заключается в том, что эти методы не уведомляют платформу о том, что сам ссылочный объект (в нашем примере РесурснаяСпецификация) изменился, и его кэшированные свойства должны быть перечитаны.
ОповеститьОбИзменении()Для решения описанной проблемы нам необходимо явно уведомить систему 1С о том, что один или несколько объектов изменились, и формы, отображающие их свойства, должны обновить свои данные. Именно для этих целей в платформе существует метод ОповеститьОбИзменении().
ОповеститьОбИзменении()?Метод ОповеститьОбИзменении(<Ссылка>) является мощным инструментом для управления отображением данных в управляемых формах. Он выполняет следующие действия:
<Ссылка>, был изменен.ОповеститьОбИзменении() в нашем сценарииВ нашем случае, когда мы изменили реквизиты НачалоДействия или КонецДействия у объекта РесурснаяСпецификация, нам нужно оповестить систему именно об изменении этого объекта. Если в табличной части у нас несколько строк, и каждая строка ссылается на свою РесурснуюСпецификацию, или даже если несколько строк ссылаются на одну и ту же спецификацию, мы должны пройтись по всем уникальным ссылкам на РесурсныеСпецификации и оповестить систему об их изменении.
Решение, которое помогло автору темы, выглядит следующим образом:
Для каждого СтрокаНоменклатура Из Объект.Номенклатура Цикл
ОповеститьОбИзменении(СтрокаНоменклатура.РесурснаяСпецификация);
КонецЦикла;
Разберем этот код по шагам:
Для каждого СтрокаНоменклатура Из Объект.Номенклатура Цикл: Мы итерируемся по каждой строке табличной части "Номенклатура" нашей обработки.СтрокаНоменклатура.РесурснаяСпецификация: В каждой строке мы получаем ссылку на объект РесурснаяСпецификация, который связан с данной строкой.ОповеститьОбИзменении(СтрокаНоменклатура.РесурснаяСпецификация): Для каждой уникальной ссылки на РесурснуюСпецификацию мы вызываем метод ОповеститьОбИзменении(). Это гарантирует, что платформа будет проинформирована о том, что данные конкретной спецификации могли измениться, и все формы, отображающие ее свойства, должны обновиться.Важный аспект: Клиент и Сервер
Следует помнить, что метод ОповеститьОбИзменении(), как и большинство методов, связанных с интерактивным отображением данных, должен вызываться на клиенте. Если изменения в РесурснойСпецификации происходят в серверной процедуре, вам нужно убедиться, что после выполнения серверного кода управление возвращается на клиент, и именно на клиенте вызывается ОповеститьОбИзменении() для каждой измененной ссылки.
Например, если ваша серверная процедура заполняет табличную часть, то после ее завершения (когда управление уже на клиенте) вы можете вызвать цикл с ОповеститьОбИзменении(). Или, если изменение объекта происходит полностью на клиенте, вызов делается непосредственно после изменения.
Хотя ОповеститьОбИзменении() является основным решением для описанной проблемы, существуют и другие методы обновления данных, которые могут быть полезны в различных сценариях. Давайте рассмотрим их:
ЭтаФорма.Прочитать():
Элементы.Список.Обновить():
ОповеститьОбИзмененииОбъектов(Источник, ДополнительныеПараметры):
ОповеститьОбИзменении() в цикле для большого количества объектов, если он реализован с пакетной обработкой.Оповестить(<ИмяСобытия>, <Параметр>, <Источник>):
ОбработкаОповещения() для реакции на такие сообщения.ПолучитьФорму():
ПолучитьФорму() и затем вызвать Обновить() или ОбновитьОтображениеДанных() у нужного элемента.В некоторых случаях, если проблема кэширования носит более глубокий характер и связана с некорректным поведением платформы после динамического обновления конфигурации, сбоев или проблем с целостностью данных, может потребоваться ручная очистка пользовательского кэша. Это более радикальный шаг, который обычно применяется для решения проблем на уровне платформы, а не для рядовых обновлений данных в работающей конфигурации.
Для этого можно удалить файлы из каталогов, где хранится кэш, например, C:\Users\User\AppData\Local\1C и C:\Users\User\AppData\Roaming\1C. Однако это следует делать осторожно и только после исчерпания других программных методов, так как это повлияет на всех пользователей на данном компьютере и сбросит все кэшированные данные платформы.
Проблема с кэшированием данных реквизитов ссылочного типа в управляемых формах 1С является распространенной. Мы выяснили, что стандартные методы обновления отображения формы часто неэффективны, когда речь идет о свойствах объектов, на которые ссылаются реквизиты табличных частей или другие элементы формы. Ключевым и наиболее эффективным решением в такой ситуации является метод ОповеститьОбИзменении(<Ссылка>). Этот метод позволяет явно указать системе, что конкретный объект изменился, и все формы, отображающие его данные, должны актуализироваться, гарантируя, что пользователи всегда видят актуальную информацию.