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