К статье
Практический материал

Разработка и Конфигурация · 12 мин

1С: как обновить форму на клиенте — практическое руководство

Как обновить форму на клиенте в 1С: методы Прочитать(), ОбновитьОтображениеДанных(), оповещения между формами. Примеры кода, ошибки и проверка результата.

Задача обновить форму на клиенте в 1С возникает почти в каждой разработке: данные объекта изменились на сервере, пользователь отредактировал связанный элемент в другой форме, фоновое задание завершилось — а интерфейс показывает устаревшие значения. Платформа 1С:Предприятие 8.3 предлагает несколько механизмов обновления, и выбор между ними влияет не только на корректность данных, но и на скорость работы формы.

Главная ловушка — путать «обновить отображение» и «перечитать данные». Первое лишь перерисовывает элементы формы на основании уже имеющихся в памяти данных, второе заново загружает объект из базы. Если применить не тот метод, форма либо не покажет свежие данные, либо без нужды дергает базу запросами.

Ниже разобраны рабочие способы обновления: от простого вызова ОбновитьОтображениеДанных() до оповещений между формами и обработчиков ожидания. Примеры приведены для управляемых форм с разделением клиентского и серверного контекста.

Различие между перерисовкой и перечитыванием данных

Прежде чем писать код, нужно понять, что именно требуется форме. Если данные реквизитов уже изменены в памяти (например, программно присвоены новые значения), достаточно заставить форму перерисовать элементы — это делает метод ОбновитьОтображениеДанных(). Он не обращается к базе и работает мгновенно.

Если же объект изменился в базе данных — другим пользователем, регламентным заданием или серверной процедурой без возврата объекта — простой перерисовки недостаточно. Потребуется вызвать Прочитать() на сервере, чтобы объект формы загрузил актуальное состояние из СУБД. Это более дорогая операция, и злоупотреблять ею не стоит.

Третий случай — изменились данные прикладного типа, отображаемые в динамическом списке или табличной части, заполненной запросом. Здесь помогает метод Элементы.ИмяСписка.Обновить(), который повторно выполняет запрос списка без перечитывания всей формы.

Метод ОбновитьОтображениеДанных() — базовый способ

Метод ОбновитьОтображениеДанных() доступен на клиенте и применяется к форме целиком или к конкретному элементу. Он заставляет платформу заново вывести значения реквизитов в связанные поля ввода, таблицы и надписи.

Типичный сценарий: в клиентской процедуре программно меняется реквизит формы, и нужно, чтобы пользователь сразу увидел результат. Пример:

&НаКлиенте

Процедура ПересчитатьИтог(Команда)

Объект.СуммаДокумента = Объект.Товары.Итог("Сумма");

ОбновитьОтображениеДанных();

КонецПроцедуры

Если нужно обновить только один элемент, передайте его в параметре: ОбновитьОтображениеДанных(Элементы.СуммаДокумента). Это снижает нагрузку на отрисовку в сложных формах с десятками полей.

Важно понимать ограничение: метод не читает базу. Если значение изменил другой сеанс, ОбновитьОтображениеДанных() покажет старые данные из памяти формы.

Перечитывание объекта через Прочитать() на сервере

Когда данные объекта могли измениться в базе, форму обновляют серверным вызовом Прочитать(). Метод объекта формы загружает текущую версию из СУБД и заменяет данные в реквизите Объект. После этого платформа автоматически обновляет отображение связанных элементов.

Пример кнопки «Обновить из базы»:

&НаКлиенте

Процедура ОбновитьИзБазы(Команда)

ПеречитатьОбъектНаСервере();

КонецПроцедуры

&НаСервере

Процедура ПеречитатьОбъектНаСервере()

Прочитать();

КонецПроцедуры

Главный риск этого подхода — потеря несохранённых изменений. Если пользователь уже редактировал форму, Прочитать() затрёт его правки данными из базы. Поэтому перед перечитыванием проверяйте флаг модифицированности и при необходимости спрашивайте подтверждение:

&НаКлиенте

Процедура ОбновитьИзБазы(Команда)

Если Модифицированность Тогда

ПоказатьВопрос(Новый ОписаниеОповещения("ОбновитьИзБазыЗавершение", ЭтотОбъект),

"Несохранённые изменения будут потеряны. Продолжить?",

РежимДиалогаВопрос.ДаНет);

Иначе

ПеречитатьОбъектНаСервере();

КонецЕсли;

КонецПроцедуры

Обновление динамических списков и табличных частей

Формы списков документов и справочников построены на динамических списках. Чтобы список показал свежие записи, вызовите метод Обновить() у элемента формы, связанного со списком:

&НаКлиенте

Процедура ОбновитьСписок(Команда)

Элементы.Список.Обновить();

КонецПроцедуры

Метод повторно выполняет запрос динамического списка, при этом текущая позиция курсора по возможности сохраняется. Это дешевле, чем пересоздание формы, и не затрагивает настройки отбора и сортировки, заданные пользователем.

Для табличных частей, заполненных программно, отдельный вызов обновления обычно не нужен: после изменения коллекции достаточно ОбновитьОтображениеДанных(Элементы.Товары). Но если табличная часть заполняется запросом на сервере, не забудьте вернуть результат в реквизит формы — иначе клиентская сторона не увидит изменений.

Оповещения между формами: Оповестить и ОповеститьОбИзменении

Самый правильный способ обновить форму после редактирования в другой форме — механизм оповещений. Форма-источник вызывает Оповестить() или ОповеститьОбИзменении(), а форма-приёмник обрабатывает событие в ОбработкаОповещения().

Для типовых объектов платформа сама рассылает стандартное оповещение при записи. В форме списка достаточно реализовать обработчик:

&НаКлиенте

Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)

Если ИмяСобытия = "Запись_Номенклатура" Тогда

Элементы.Список.Обновить();

КонецЕсли;

КонецПроцедуры

Метод ОповеститьОбИзменении(Ссылка) вызывается на клиенте и уведомляет все открытые формы, что конкретный объект изменился. Формы, отображающие этот объект, могут перечитать его, а списки — обновить строку. Это удобно, когда объект записан программно на сервере и стандартное оповещение не сработало.

Пользовательское событие через Оповестить("МоёСобытие", Параметры, Источник) подходит для нестандартных сценариев: например, обновить форму-владельца после выбора значения в форме подбора. Обязательно проверяйте ИмяСобытия в обработчике, чтобы не реагировать на чужие оповещения.

Порядок настройки обновления через оповещения
  1. 1
    В форме-источнике после записи вызовите Оповестить() с уникальным именем события
  2. 2
    В форме-приёмнике создайте обработчик ОбработкаОповещения()
  3. 3
    Внутри проверьте ИмяСобытия и при совпадении вызовите Элементы.Список.Обновить() или Прочитать()
  4. 4
    Протестируйте: измените объект в одной форме и убедитесь, что вторая обновилась без переоткрытия

Периодическое обновление через обработчики ожидания

Иногда форму нужно обновлять по таймеру: монитор очереди заказов, панель показателей, статус фонового задания. Для этого служит метод ПодключитьОбработчикОжидания(), который вызывает указанную клиентскую процедуру с заданным интервалом.

&НаКлиенте

Процедура ПриОткрытии(Отказ)

ПодключитьОбработчикОжидания("ОбновитьСтатус", 30);

КонецПроцедуры

&НаКлиенте

Процедура ОбновитьСтатус()

Элементы.Список.Обновить();

КонецПроцедуры

Интервал задаётся в секундах. Не ставьте слишком маленькие значения: каждый вызов может инициировать серверный обмен, и при интервале в несколько секунд нагрузка на сервер и канал связи заметно вырастет, особенно при большом числе пользователей.

При закрытии формы обработчик отключается автоматически, но если вы подключаете его по условию в процессе работы, отключайте через ОтключитьОбработчикОжидания(), когда обновление больше не нужно.

Для мониторинга фоновых заданий разумнее обновлять форму по событию завершения (через оповещение или проверку состояния раз в 5–10 секунд), чем дергать сервер каждую секунду. Пользователь вряд ли заметит задержку в пару секунд, а сервер скажет спасибо.
ПЗ
Практическое замечание

Типичные ошибки и как их избежать

Наиболее частая ошибка — вызов Прочитать() в клиентском контексте. Метод доступен только на сервере, поэтому код оформляют как отдельную серверную процедуру. Попытка вызвать его из клиентской процедуры приведёт к ошибке компиляции или выполнения.

Вторая распространённая проблема — обновление списка по имени реквизита вместо элемента формы. Метод Обновить() принадлежит элементу (таблице формы), а не реквизиту данных, поэтому правильно писать Элементы.Список.Обновить().

Третья ошибка — избыточные серверные вызовы в цикле. Если нужно обновить много строк или несколько списков, объединяйте логику в один серверный вызов, а не вызывайте серверную процедуру на каждую итерацию.

Типичные ошибки
01
Вызов Прочитать() из клиентской процедуры — метод работает только на сервере
02
ОбновитьОтображениеДанных() вместо перечитывания — форма показывает устаревшие данные из памяти
03
Прочитать() без проверки Модифицированность — теряются несохранённые правки пользователя
04
Слишком частый обработчик ожидания — лишняя нагрузка на сервер и сеть
05
Обращение к реквизиту вместо элемента формы при обновлении списка

Как проверить, что обновление сработало

После внедрения обновления проверьте поведение формы в реальных сценариях. Откройте один и тот же объект в двух сеансах (или в двух окнах), измените его в одном и убедитесь, что вторая форма корректно реагирует: показывает свежие данные после оповещения или по кнопке обновления.

Для динамических списков проверьте, что после Обновить() сохраняются отбор, сортировка и текущая строка. Если курсор сбрасывается на первую запись, это признак того, что список пересоздаётся, а не обновляется — проверьте, не меняете ли вы программно текст запроса или параметры.

Контрольные точки

Как проверить результат

Отображение данных после правки в другой форме
Норма

Значения обновились без переоткрытия формы

Тревожный признак

Форма показывает старые данные до закрытия и повторного открытия

Состояние списка после Обновить()
Норма

Сохранены отбор, сортировка и текущая строка

Тревожный признак

Курсор сбрасывается, настройки списка слетают

Работа с несохранёнными изменениями
Норма

Перед перечитыванием выдаётся вопрос о потере изменений

Тревожный признак

Правки пользователя исчезают без предупреждения

Какой способ выбрать в конкретной ситуации

Выбор метода зависит от источника изменения данных. Сводная логика принятия решения приведена ниже.

Маршрут решения

Как выбрать действие

Данные изменены программно в памяти формыВызовите ОбновитьОтображениеДанных() — базу трогать не нужно
Объект мог измениться в базе данныхВызовите Прочитать() на сервере, предварительно проверив Модифицированность
Изменились записи, показываемые динамическим спискомВызовите Элементы.Список.Обновить()
Объект отредактирован в другой открытой формеИспользуйте ОповеститьОбИзменении() или Оповестить() с обработчиком ОбработкаОповещения
Нужен регулярный мониторинг измененийПодключите обработчик ожидания с разумным интервалом от 10–30 секунд
Итог

Что важно запомнить

ОбновитьОтображениеДанных() перерисовывает форму по данным в памяти, Прочитать() перечитывает объект из базы на сервере, Элементы.Список.Обновить() обновляет динамический список, а оповещения связывают между собой открытые формы. Перед перечитыванием всегда проверяйте модифицированность, чтобы не потерять правки пользователя.

Часто задаваемые вопросы

Можно ли вызвать Прочитать() прямо на клиенте?

Нет, метод доступен только в серверном контексте формы. Создайте процедуру с директивой &НаСервере, вызовите в ней Прочитать(), а из клиентской процедуры обращайтесь к этой серверной обёртке.

Почему после ОбновитьОтображениеДанных() данные остались старыми?

Метод не читает базу, а лишь перерисовывает элементы по текущим данным в памяти. Если объект изменён другим сеансом, сначала перечитайте его через Прочитать() на сервере, затем отображение обновится автоматически.

Как обновить форму списка после записи элемента в форме объекта?

Стандартная запись объекта сама рассылает оповещение, и динамический список обычно обновляется автоматически. Если этого не происходит (например, запись выполнена программно), вызовите на клиенте ОповеститьОбИзменении(Ссылка) или обработайте событие в ОбработкаОповещения() с вызовом Элементы.Список.Обновить().

Какой интервал выбрать для обработчика ожидания?

Зависит от сценария, но опускаться ниже 5–10 секунд не стоит: каждый цикл может порождать серверный вызов. Для мониторинга фоновых заданий обычно достаточно 5–15 секунд, для сводных панелей — 30 и более.

Сохраняется ли позиция курсора при обновлении динамического списка?

Да, метод Обновить() старается сохранить текущую строку, отбор и сортировку. Позиция теряется, если запись удалена или если вы программно меняете текст запроса или ключевые параметры списка — тогда список фактически пересоздаётся.

Чем ОповеститьОбИзменении() отличается от Оповестить()?

ОповеститьОбИзменении() — специализированный вызов для конкретной ссылки на объект: формы, отображающие этот объект, получают стандартное уведомление. Оповестить() — универсальный механизм с произвольным именем события и параметрами, требующий собственного обработчика в форме-приёмнике.