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