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

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

1С: как перечитать открытую форму программно

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

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

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

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

Чем перечитывание отличается от обновления отображения

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

В управляемых формах данные объекта хранятся в реквизите формы (обычно это реквизит Объект типа ДанныеФормыСтруктура). Метод ОбновитьОтображениеДанных() заставляет форму заново вывести значения этого реквизита в элементы интерфейса. Метод Объект.Прочитать() (доступный на сервере через преобразование данных формы в объект) загружает данные из базы заново.

Способ 1. Метод Прочитать() в объектной форме

Если нужно перечитать данные внутри самой объектной формы (документа, справочника), используется серверная процедура. Данные формы преобразуются в прикладной объект методом РеквизитФормыВЗначение(), объект читается из базы, затем значение возвращается обратно в форму через ЗначениеВРеквизитФормы().

&НаСервере

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

ТекущийОбъект = РеквизитФормыВЗначение("Объект");

ТекущийОбъект.Прочитать();

ЗначениеВРеквизитФормы(ТекущийОбъект, "Объект");

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

После такого перечитывания форма получает свежие данные из базы, включая изменения, внесённые другими пользователями или фоновыми заданиями. Учтите, что все несохранённые изменения, сделанные пользователем в форме, будут потеряны — перечитывание фактически откатывает редактирование.

Вызов через встроенную команду формы

У управляемой формы объекта есть стандартный метод Прочитать(), вызываемый непосредственно у формы: он выполняет то же действие, что команда «Перечитать» в меню «Ещё». Вызов ЭтаФорма.Прочитать() доступен на клиенте и не требует серверной процедуры — это самый короткий способ перечитать объектную форму из её собственного кода.

Способ 2. Обновление динамического списка

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

&НаКлиенте

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

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

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

Этот вызов заставляет динамический список заново выполнить запрос к базе и перестроить строки. Если у списка включено автообновление, данные перечитываются самой платформой с заданным периодом, но программный вызов даёт обновление немедленно — например, после записи нового элемента из другой формы.

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

Способ 3. Оповещения между формами

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

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

&НаКлиенте

Процедура ПослеЗаписиФоновогоИзменения()

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

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

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

// В форме-источнике:

Оповестить("ИзмененыЦеныНоменклатуры", ПараметрыСобытия, ЭтаФорма);

// В целевой форме:

&НаКлиенте

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

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

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

КонецЕсли;

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

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

Способ 4. ОбновитьОтображениеДанных — когда он нужен

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

&НаКлиенте

Процедура ПослеЗаполненияТаблицы()

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

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

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

Сравнение способов обновления формы

ЭтаФорма.Прочитать()

Перечитывает объект из базы в объектной форме. Теряются несохранённые изменения; не работает для форм списков.

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

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

ОповеститьОбИзменении(Ссылка)

Штатное уведомление всех открытых форм об изменении объекта. Не передаёт произвольные параметры.

Оповестить + ОбработкаОповещения

Гибкий сценарий с произвольным событием и параметрами. Требует кода в обеих формах и контроля уникальности имён событий.

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

Только перерисовка формы из данных в памяти. Не читает базу и не заменяет перечитывание.

Проверка результата и типичные ошибки

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

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

Ещё одна распространённая проблема — обращение к элементу формы по неверному имени. Если таблица списка называется не Список, а, например, СписокДокументов, вызов Элементы.Список.Обновить() завершится ошибкой. Всегда сверяйте имя элемента в дереве элементов формы в конфигураторе.

Ограничения и частные сценарии

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

Для форм, открытых в толстом клиенте или через веб-клиент, механизм оповещений работает одинаково, но стоит учитывать, что серверные вызовы в веб-клиенте дороже по времени. Если обновление требует тяжёлого серверного пересчёта, выполняйте его асинхронно или показывайте пользователю индикатор длительной операции.

Отдельный случай — обновление формы из фонового задания. Фоновое задание не имеет доступа к формам напрямую; результат передаётся через механизм длительных операций с оповещением формы-владельца по завершении. Пытаться «дотянуться» до открытой формы из фонового сеанса нельзя — это архитектурное ограничение платформы.

Итог

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

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

Частые вопросы

Как перечитать форму объекта из другой формы напрямую?

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

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

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

Как обновить только одну строку динамического списка?

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

Оповещение отправлено, но обработчик не срабатывает. Что проверить?

Сверьте посимвольно имя события в Оповестить() и в ОбработкаОповещения — платформа не сообщает об опечатках. Убедитесь, что целевая форма открыта в момент оповещения и что обработчик объявлен именно в модуле формы, а не в общем модуле.

Как не потерять несохранённые данные при перечитывании?

Перед вызовом Прочитать() проверьте свойство Модифицированность формы. Если оно истинно, задайте пользователю вопрос через ПоказатьВопрос() и перечитывайте объект только после подтверждения, либо предложите сначала записать изменения.

Можно ли обновить форму из фонового задания?

Напрямую — нет: фоновое задание выполняется в отдельном сеансе без доступа к клиентским формам. Используйте механизм длительных операций: по завершении задания клиентская форма получает оповещение и обновляет данные штатными методами.