Как обновить данные реквизитов ссылочного типа, кэшируемые в управляемой форме 1С, при использовании интерфейса "Такси"?

Программист 1С v8.3 (Управляемые формы)
← На главную

При работе с управляемыми формами в 1С:Предприятии, особенно в режиме "Такси", мы можем столкнуться с ситуацией, когда данные, отображаемые на форме, не соответствуют актуальным значениям в базе данных. Это особенно характерно для реквизитов ссылочного типа, чьи свойства выведены на форму. Давайте подробно разберем эту проблему и найдем эффективное решение.

Суть проблемы: кэширование данных ссылочных реквизитов на форме

Представим, что у нас есть внешняя обработка с табличной частью, например, "Номенклатура". В этой табличной части имеется реквизит РесурснаяСпецификация, который ссылается на справочник СправочникСсылка.РесурсныеСпецификации. У этого справочника есть свои реквизиты, такие как НачалоДействия и КонецДействия, которые мы вынесли прямо на форму обработки в виде колонок табличной части.

Ситуация, с которой мы можем столкнуться, следующая: при первоначальном заполнении табличной части формы 1С запоминает значения реквизитов НачалоДействия и КонецДействия для каждой РесурснойСпецификации. Если позже эти реквизиты будут изменены непосредственно в базе данных (например, через другую форму, программно или вручную), то на нашей форме обработки эти изменения никак не отразятся. Более того, мы можем обнаружить, что даже переоткрытие обработки или повторное заполнение табличной части не приводит к актуализации данных. Форма упорно продолжает показывать старые, кэшированные значения.

Это происходит потому, что платформа 1С использует многоуровневое кэширование для оптимизации производительности. Кэш, относящийся к конкретной форме, сбрасывается только при ее полном закрытии или при явном указании системе, что связанные объекты были изменены. Когда мы отображаем реквизиты ссылочного объекта (например, РесурснаяСпецификация.КонецДействия), форма кэширует не только ссылку на объект, но и представление его данных. Если сам объект РесурснаяСпецификация изменяется, форма не всегда автоматически понимает, что нужно обновить его отображаемые свойства.

Неудачные попытки обновления данных

Многие разработчики, столкнувшись с такой проблемой, в первую очередь пробуют стандартные методы обновления отображения данных. Давайте рассмотрим, какие из них обычно не помогают в данном сценарии:

  1. ЭтаФорма.ОбновитьОтображениеДанных(): Этот метод обновляет содержимое элементов управления формы, но он ориентирован в первую очередь на реквизиты самого объекта формы или на элементы, связанные с ее основным объектом. В нашем случае, когда проблема касается свойств ссылочного объекта, выведенных на форму, этот метод часто оказывается бессильным.
  2. ЭтаФорма.ОбновитьОтображениеДанных(Элементы.ИмяЭлемента): Попытка указать конкретный элемент (например, табличную часть Номенклатура или даже отдельную колонку НоменклатураРесурснаяСпецификацияКонецДействия) также не приносит желаемого результата. Система обновляет отображение, но берет данные из того же кэша, который содержит устаревшие значения для свойств ссылочного объекта.
  3. Элементы.ИмяЭлемента.Обновить(): Для табличных частей, представленных динамическими списками, метод Обновить() заставляет список перечитать свои данные. Однако в нашем случае табличная часть является реквизитом формы, а не динамическим списком. И даже если бы это был динамический список, проблема кэширования свойств вложенного объекта могла бы остаться.

Как мы видим из обсуждения на форуме, эти подходы были опробованы и не привели к решению:


&НаКлиенте
Процедура ОбновитьТаблицу(Команда)
    ЭтаФорма.ОбновитьОтображениеДанных(); // не помогает
    ЭтаФорма.ОбновитьОтображениеДанных(Элементы.Номенклатура); // не помогает
    ЭтаФорма.ОбновитьОтображениеДанных(Элементы.НоменклатураРесурснаяСпецификацияКонецДействия); // не помогает
    Элементы.Номенклатура.Обновить(); // не помогает
КонецПроцедуры

Ключевая проблема здесь заключается в том, что эти методы не уведомляют платформу о том, что сам ссылочный объект (в нашем примере РесурснаяСпецификация) изменился, и его кэшированные свойства должны быть перечитаны.

Эффективное решение: использование метода ОповеститьОбИзменении()

Для решения описанной проблемы нам необходимо явно уведомить систему 1С о том, что один или несколько объектов изменились, и формы, отображающие их свойства, должны обновить свои данные. Именно для этих целей в платформе существует метод ОповеститьОбИзменении().

Как работает ОповеститьОбИзменении()?

Метод ОповеститьОбИзменении(<Ссылка>) является мощным инструментом для управления отображением данных в управляемых формах. Он выполняет следующие действия:

  1. Уведомление системы: Он информирует всю систему 1С (все открытые формы, динамические списки) о том, что объект, на который указывает переданная <Ссылка>, был изменен.
  2. Сброс кэша: Для всех форм и динамических списков, которые каким-либо образом отображают данные или свойства этого объекта, платформа инициирует процесс перечитывания актуальных данных из базы данных.
  3. Автоматическое обновление: Разработчику не нужно отслеживать, какие именно формы открыты и какие элементы отображают данный объект. Система автоматически обрабатывает оповещение и вызывает необходимые механизмы обновления.

Применение ОповеститьОбИзменении() в нашем сценарии

В нашем случае, когда мы изменили реквизиты НачалоДействия или КонецДействия у объекта РесурснаяСпецификация, нам нужно оповестить систему именно об изменении этого объекта. Если в табличной части у нас несколько строк, и каждая строка ссылается на свою РесурснуюСпецификацию, или даже если несколько строк ссылаются на одну и ту же спецификацию, мы должны пройтись по всем уникальным ссылкам на РесурсныеСпецификации и оповестить систему об их изменении.

Решение, которое помогло автору темы, выглядит следующим образом:


Для каждого СтрокаНоменклатура Из Объект.Номенклатура Цикл
    ОповеститьОбИзменении(СтрокаНоменклатура.РесурснаяСпецификация);
КонецЦикла;

Разберем этот код по шагам:

  1. Для каждого СтрокаНоменклатура Из Объект.Номенклатура Цикл: Мы итерируемся по каждой строке табличной части "Номенклатура" нашей обработки.
  2. СтрокаНоменклатура.РесурснаяСпецификация: В каждой строке мы получаем ссылку на объект РесурснаяСпецификация, который связан с данной строкой.
  3. ОповеститьОбИзменении(СтрокаНоменклатура.РесурснаяСпецификация): Для каждой уникальной ссылки на РесурснуюСпецификацию мы вызываем метод ОповеститьОбИзменении(). Это гарантирует, что платформа будет проинформирована о том, что данные конкретной спецификации могли измениться, и все формы, отображающие ее свойства, должны обновиться.

Важный аспект: Клиент и Сервер

Следует помнить, что метод ОповеститьОбИзменении(), как и большинство методов, связанных с интерактивным отображением данных, должен вызываться на клиенте. Если изменения в РесурснойСпецификации происходят в серверной процедуре, вам нужно убедиться, что после выполнения серверного кода управление возвращается на клиент, и именно на клиенте вызывается ОповеститьОбИзменении() для каждой измененной ссылки.

Например, если ваша серверная процедура заполняет табличную часть, то после ее завершения (когда управление уже на клиенте) вы можете вызвать цикл с ОповеститьОбИзменении(). Или, если изменение объекта происходит полностью на клиенте, вызов делается непосредственно после изменения.

Дополнительные методы обновления данных и очистки кэша

Хотя ОповеститьОбИзменении() является основным решением для описанной проблемы, существуют и другие методы обновления данных, которые могут быть полезны в различных сценариях. Давайте рассмотрим их:

  1. ЭтаФорма.Прочитать():
    • Назначение: Этот метод обновляет основной объект управляемой формы, фактически перечитывая все его реквизиты из базы данных.
    • Когда использовать: Эффективен, если проблема заключается именно в отображении основных реквизитов объекта самой формы, а не свойств ссылочных объектов, выведенных на форму. Например, если изменились собственные реквизиты вашей внешней обработки.
  2. Элементы.Список.Обновить():
    • Назначение: Применяется для обновления динамических списков, размещенных на форме. Он заставляет динамический список перечитать данные из источника.
    • Когда использовать: Если ваша табличная часть представлена динамическим списком (т.е. источником данных является динамический список, а не реквизит типа ТаблицаЗначений).
  3. ОповеститьОбИзмененииОбъектов(Источник, ДополнительныеПараметры):
    • Назначение: Этот метод, часто встречающийся в типовых конфигурациях (например, через Библиотеку Стандартных Подсистем - БСП), позволяет оповещать открытые формы и динамические списки об изменении сразу нескольких объектов.
    • Когда использовать: Когда у вас есть список измененных объектов, и вы хотите оповестить систему о всех них одним вызовом. Это может быть более оптимизированным, чем вызов ОповеститьОбИзменении() в цикле для большого количества объектов, если он реализован с пакетной обработкой.
  4. Оповестить(<ИмяСобытия>, <Параметр>, <Источник>):
    • Назначение: Это более общий механизм оповещения. Он позволяет посылать произвольные события всем открытым формам. Принимающая форма должна иметь обработчик события ОбработкаОповещения() для реакции на такие сообщения.
    • Когда использовать: Для реализации произвольного межформенного взаимодействия, когда стандартные механизмы обновления не подходят, и вам нужна более гибкая логика обработки событий. Механизм оповещения работает на клиенте, поэтому с сервера нельзя напрямую послать оповещение формам.
  5. Обновление извне с помощью ПолучитьФорму():
    • Назначение: Если известна конкретная открытая форма, которую нужно обновить, и известно название ее элементов, можно получить экземпляр формы с помощью ПолучитьФорму() и затем вызвать Обновить() или ОбновитьОтображениеДанных() у нужного элемента.
    • Когда использовать: В специфических сценариях, когда вы точно знаете, какую форму и какой элемент нужно обновить, но этот способ менее гибок и требует точного знания структуры формы. Он часто используется для обновления форм, которые не связаны с основным объектом текущей формы через стандартные механизмы.

Ручная очистка пользовательского кэша

В некоторых случаях, если проблема кэширования носит более глубокий характер и связана с некорректным поведением платформы после динамического обновления конфигурации, сбоев или проблем с целостностью данных, может потребоваться ручная очистка пользовательского кэша. Это более радикальный шаг, который обычно применяется для решения проблем на уровне платформы, а не для рядовых обновлений данных в работающей конфигурации.

Для этого можно удалить файлы из каталогов, где хранится кэш, например, C:\Users\User\AppData\Local\1C и C:\Users\User\AppData\Roaming\1C. Однако это следует делать осторожно и только после исчерпания других программных методов, так как это повлияет на всех пользователей на данном компьютере и сбросит все кэшированные данные платформы.

Заключение

Проблема с кэшированием данных реквизитов ссылочного типа в управляемых формах 1С является распространенной. Мы выяснили, что стандартные методы обновления отображения формы часто неэффективны, когда речь идет о свойствах объектов, на которые ссылаются реквизиты табличных частей или другие элементы формы. Ключевым и наиболее эффективным решением в такой ситуации является метод ОповеститьОбИзменении(<Ссылка>). Этот метод позволяет явно указать системе, что конкретный объект изменился, и все формы, отображающие его данные, должны актуализироваться, гарантируя, что пользователи всегда видят актуальную информацию.

← На главную