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