Разработка и Конфигурация · 13 мин
Как программно обновить форму документа в 1С
Как программно обновить форму документа в 1С: методы ОбновитьОтображениеДанных, Прочитать, перечитывание реквизитов, обновление после записи. Примеры кода и типичные ошибки.
Форма документа в 1С отображает данные объекта, но при программных изменениях — записи из фоновой процедуры, обработке заполнения, изменении связанных данных — отображение может устареть. Пользователь видит старые значения, хотя в базе данные уже другие. Чтобы интерфейс соответствовал реальному состоянию объекта, форму нужно обновить программно.
В управляемых формах для этого существует несколько инструментов: метод ОбновитьОтображениеДанных(), перечитывание объекта через Прочитать(), обновление отдельных реквизитов формы, а также оповещения между формами. Выбор зависит от того, что именно изменилось: данные самого документа, связанные объекты или внешний источник.
Ниже разобраны все рабочие способы с примерами кода, условиями применения и типичными ошибками, которые приводят к «залипанию» интерфейса или потере введённых пользователем данных.
Что происходит при обновлении формы и почему она «залипает»
Управляемая форма работает с кэшем данных на клиенте. Когда документ изменяется программно — например, серверная процедура записала объект или изменила связанный регистр — клиентская часть об этом не узнаёт автоматически. Форма продолжает показывать те значения, которые были загружены при открытии или последнем перечитывании.
Типичные ситуации, когда требуется программное обновление: после вызова Записать() в обработчике, после фонового выполнения длительной операции, после закрытия формы подбора, где пользователь выбрал товары, после изменения документа другим пользователем или регламентным заданием. Во всех этих случаях интерфейс нужно принудительно синхронизировать с данными.
Важно различать два уровня обновления: перерисовку элементов формы (без обращения к базе) и перечитывание самого объекта из базы данных. Первое дёшево по ресурсам, второе — реальное обращение к СУБД, и злоупотреблять им в часто вызываемых обработчиках не стоит.
ОбновитьОтображениеДанных — основной способ перерисовать форму
Метод ОбновитьОтображениеДанных() — самый лёгкий способ обновить форму. Он не читает данные из базы, а заставляет форму заново вывести значения, которые уже находятся в её реквизитах. Этого достаточно, если изменения произошли внутри самой формы: программно заполнен реквизит, пересчитана табличная часть, изменилось условное оформление.
Пример обновления всей формы после программного изменения реквизита:
&НаКлиенте
Процедура УстановитьСкидку(Команда)
УстановитьСкидкуНаСервере();
// Перерисовываем элементы формы
ЭтаФорма.ОбновитьОтображениеДанных();
КонецПроцедуры
&НаСервере
Процедура УстановитьСкидкуНаСервере()
Объект.Скидка = 10;
ПересчитатьСуммы();
КонецПроцедуры
Если нужно обновить только конкретный реквизит, передайте его в параметре — это сокращает объём перерисовки:
// Обновить только элементы, связанные с табличной частью "Товары"
ЭтаФорма.ОбновитьОтображениеДанных(Элементы.Товары);
Перечитывание объекта из базы методом Прочитать
Когда данные документа изменились вне текущей формы — другой пользователь провёл документ, регламентное задание обновило статусы, внешняя обработка записала объект — требуется полное перечитывание. Для этого форма объекта предоставляет метод Прочитать(), который загружает актуальные данные из базы в реквизит формы «Объект».
&НаКлиенте
Процедура ОбновитьДанныеДокумента(Команда)
ПрочитатьДанныеНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПрочитатьДанныеНаСервере()
// Перечитываем объект из базы данных
ЭтаФорма.Прочитать();
КонецПроцедуры
У этого способа есть критичное ограничение: перечитывание затирает все несохранённые изменения, которые пользователь ввёл в форму. Если документ модифицирован, перед вызовом Прочитать() нужно либо записать объект, либо предупредить пользователя и запросить подтверждение.
Проверить наличие несохранённых изменений можно через свойство Модифицированность формы. Безопасный шаблон выглядит так:
&НаКлиенте
Процедура ОбновитьИзБазы(Команда)
Если ЭтаФорма.Модифицированность Тогда
ПоказатьВопрос(
Новый ОписаниеОповещения("ОбновитьИзБазыЗавершение", ЭтотОбъект),
"Несохранённые изменения будут потеряны. Продолжить?",
РежимДиалогаВопрос.ДаНет);
Иначе
ПрочитатьДанныеНаСервере();
КонецЕсли;
КонецПроцедуры
Обновление формы из других форм через оповещения
Частый сценарий: из формы документа открывается форма подбора, обработки или связанного документа, и после её закрытия основная форма должна обновиться. Для этого в 1С предусмотрен механизм оповещений: одна форма отправляет событие, другая его обрабатывает.
В форме-источнике (например, обработке подбора) после выполнения действия вызывается Оповестить():
&НаКлиенте
Процедура ПеренестиВДокумент(Команда)
ПеренестиВДокументНаСервере();
// Сообщаем всем открытым формам об изменении
Оповестить("ПодборТоваровВыполнен", Объект.Ссылка, ЭтаФорма);
Закрыть();
КонецПроцедуры
В форме документа реализуется обработчик ОбработкаОповещения:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ПодборТоваровВыполнен"
И Параметр = Объект.Ссылка Тогда
ПрочитатьДанныеНаСервере();
КонецЕсли;
КонецПроцедуры
Для стандартных изменений объектов существуют типовые события: ОповеститьОбИзменении(Ссылка) отправляет событие «Запись» с типом объекта, и подписанные формы (списки, формы с динамическими списками) обновляются автоматически. Это правильный способ уведомить открытые списки документов о записи из программного кода.
- 1Определите, что изменилось: данные внутри формы или объект в базе
- 2Для изменений внутри формы вызовите ОбновитьОтображениеДанных()
- 3Для изменений в базе проверьте Модифицированность и вызовите Прочитать() на сервере
- 4Для обновления из другой формы добавьте Оповестить() и ОбработкаОповещения
- 5Проверьте результат: значения на форме совпадают с данными в базе
Обновление динамических списков и связанных табличных частей
Если на форме документа размещён динамический список — например, связанные документы или движения — он обновляется отдельно. Метод ОбновитьОтображениеДанных() формы не перечитывает запрос динамического списка. Для этого у расширения таблицы формы есть метод Обновить():
&НаКлиенте
Процедура ОбновитьСвязанныеДокументы(Команда)
Элементы.СписокСвязанныхДокументов.Обновить();
КонецПроцедуры
Для обычных (не динамических) таблиц формы, заполняемых запросом на сервере, потребуется повторный вызов серверной процедуры заполнения с последующим ОбновитьОтображениеДанных(). Универсального автоматического механизма здесь нет — логику перезаполнения реализует разработчик.
Отдельный случай — обновление после записи. В обработчике ПослеЗаписи на клиенте часто требуется обновить связанные элементы: списки, панели навигации, показатели. Типовой шаблон:
&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
// Уведомляем другие формы о записи документа
ОповеститьОбИзменении(Объект.Ссылка);
// Обновляем связанные списки на этой форме
Элементы.СписокСвязанныхДокументов.Обновить();
КонецПроцедуры
Сравнение вариантов
Изменения произошли в реквизитах самой формы. Не обращается к базе, быстрый, не подходит для внешних изменений.
Объект изменён в базе другим кодом или пользователем. Перечитывает всё, затирает несохранённые изменения.
Обновление инициируется другой формой. Требует реализации обработчика, но работает между любыми открытыми формами.
Только для динамических списков на форме. Перечитывает запрос списка, не трогает объект документа.
Обновление после фоновых и длительных операций
При использовании длительных операций (фоновых заданий через ДлительныеОперации) форма должна обновиться по завершении задания. Результат обычно возвращается через временное хранилище, а в обработчике ожидания на клиенте выполняется обновление:
&НаКлиенте
Процедура ЗагрузкаЗавершение(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат;
КонецЕсли;
Если Результат.Статус = "Выполнено" Тогда
ОбработатьРезультатНаСервере(Результат.АдресРезультата);
ЭтаФорма.ОбновитьОтображениеДанных();
Иначе
ПоказатьПредупреждение(, Результат.КраткоеПредставлениеОшибки);
КонецЕсли;
КонецПроцедуры
Если фоновое задание изменило сам документ в базе, вместо ОбновитьОтображениеДанных() нужно перечитать объект — с той же проверкой модифицированности, что описана выше. Пока выполняется длительная операция, разумно блокировать форму от редактирования, чтобы исключить конфликт изменений.
Обычные формы и особенности старых конфигураций
В обычных формах (режим обычного приложения, старые конфигурации на 8.1–8.2) механизм другой. Там форма напрямую связана с объектом, и обновление выполняется методами Обновить() формы или перечитыванием объекта через ЭтотОбъект.Прочитать(). Оповещения работают аналогично — через Оповестить() и ОбработкаОповещения.
Если конфигурация смешанная или вы поддерживаете старое решение, проверяйте режим запуска: код управляемых форм не работает в обычном приложении и наоборот. Для управляемых форм в таком случае используются директивы компиляции #Если ТолстыйКлиентОбычноеПриложение с разными ветками реализации.
Как проверить результат
Совпадают с данными объекта в базе
Форма показывает устаревшие значения после записи
Флаг сброшен после перечитывания, данные пользователя сохранены или записаны
Введённые вручную данные пропали без предупреждения
Показывают актуальные связанные записи
Новые связанные документы не появляются до переоткрытия формы
Форма обновляется только на своё событие
Форма перечитывается при любых оповещениях в системе
Частые вопросы
Почему ОбновитьОтображениеДанных() не показывает изменения, сделанные другой обработкой?
Потому что метод работает только с данными, уже загруженными в реквизиты формы, и не обращается к базе. Если объект изменён внешним кодом, нужно перечитать его вызовом ЭтаФорма.Прочитать() на сервере — тогда в форму загрузятся актуальные данные из базы.
Как обновить форму, не теряя данные, введённые пользователем?
Полное перечитывание без потери невозможно — Прочитать() затирает реквизит «Объект». Варианты: сначала записать документ, обновлять только отдельные реквизиты формы вручную (без перечитывания объекта) или запросить у пользователя подтверждение на откат изменений.
Чем отличается Оповестить() от ОповеститьОбИзменении()?
Оповестить() отправляет произвольное событие с заданным именем — обработчик нужно писать самостоятельно. ОповеститьОбИзменении(Ссылка) отправляет стандартное событие записи объекта, на которое автоматически реагируют динамические списки и стандартные формы, отображающие этот объект.
Как обновить форму списка документов после программной записи документа?
После записи вызовите ОповеститьОбИзменении(СсылкаНаДокумент) — открытые формы списков этого вида документов обновятся автоматически. Если список открыт в текущей форме, дополнительно можно вызвать Элементы.Список.Обновить().
Можно ли обновить форму документа по таймеру?
Да, через ПодключитьОбработчикОжидания("ИмяПроцедуры", Интервал) на клиенте. В обработчике выполняется серверный вызов с перечитыванием или проверкой версии данных. Учитывайте нагрузку: слишком частые серверные вызовы от множества открытых форм создают лишнюю нагрузку на сервер, поэтому интервал стоит выбирать разумным и отключать обработчик при закрытии формы.
Обновление работает в толстом клиенте, но не в тонком — в чём причина?
Чаще всего код обновления размещён в серверной процедуре без контекста или использует методы, недоступные в тонком клиенте. Проверьте директивы компиляции (&НаКлиенте, &НаСервере), доступность вызываемых методов в режиме тонкого клиента и то, что обновление отображения вызывается именно на клиенте после получения данных с сервера.
Что важно запомнить
ОбновитьОтображениеДанных() перерисовывает форму без обращения к базе, Прочитать() загружает актуальный объект, но затирает несохранённые изменения, оповещения связывают формы между собой, а динамические списки обновляются отдельным методом Обновить(). Выбор способа определяется тем, где именно изменились данные.