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