Обновление формы и перерисовка данных в 1С 8.3

· 8 мин

Содержание

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

Распространённое заблуждение — что есть одна «кнопка обновить всё». Её нет. «Обновить окно» в 1С 8.3 — это три разные задачи с разными методами, и перепутать их легко: перечитать данные из базы, обновить список строк и перерисовать внешний вид формы — не одно и то же. Разберём каждый механизм и события, которые за него отвечают, на управляемых формах платформы «Такси».

Что на самом деле значит «обновить окно»

За словом «обновить» в 1С прячутся три непохожие операции. Прежде чем писать код, определите, что именно устарело на экране.

  • 🔄 Данные формы объекта. Кто-то изменил и записал документ или элемент справочника, а у вас открыта его форма со старыми реквизитами. Нужно перечитать объект из базы.
  • 📋 Строки динамического списка. Открыт список документов, в базу добавилась новая строка, а список её не показывает. Нужно перечитать сам список.
  • 🎨 Внешний вид формы. Данные верные, но не пересчиталось условное оформление, видимость или доступность элементов. Нужно перерисовать форму, не трогая базу.

Каждой задаче — свой метод. Если применить не тот, окно либо не обновится вовсе, либо обновится лишнее и форма начнёт «тормозить». Дальше — по порядку.

Перечитать данные открытой формы

Когда у формы есть основной объект (документ, элемент справочника) и его поменяли в базе, используйте метод формы Прочитать().

&НаКлиенте
Процедура ПеречитатьВыполнить(Команда)
    Прочитать();
КонецПроцедуры

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

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

&НаКлиенте
Процедура ПриИзмененииСтавки(Элемент)
    ОбновитьОтображениеДанных();
КонецПроцедуры

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

Как обновить динамический список в окне

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

&НаКлиенте
Процедура ОбновитьСписок(Команда)
    Элементы.Список.Обновить();
КонецПроцедуры

Список здесь — имя элемента формы, а не имя реквизита. Если список называется иначе, подставьте фактическое имя из дерева элементов формы.

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

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

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

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

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

Форма-источник после записи шлёт оповещение. Удобное место — обработчик ПослеЗаписи:

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    Оповестить("ЗаписанКонтрагент", Объект.Ссылка);
КонецПроцедуры

Форма-приёмник ловит сигнал в обработчике ОбработкаОповещения и решает, что делать:

&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    Если ИмяСобытия = "ЗаписанКонтрагент" Тогда
        Элементы.СписокКонтрагентов.Обновить();
    КонецЕсли;
КонецПроцедуры

Три детали, на которых держится вся схема:

  1. Оба метода — клиентские. Оповестить() и ОбработкаОповещения работают только на клиенте. Вызов Оповестить() из серверной процедуры ничего не сделает.
  2. Имя события — обычная строка. Один и тот же текст должен стоять и в вызове Оповестить(), и в условии обработчика. Опечатка — и сигнал уходит в пустоту.
  3. Параметр произвольный. Через второй аргумент передают ссылку, структуру, что угодно — приёмник сам решает, нужно ли реагировать именно на этот объект.

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

ОповеститьОбИзменении: автообновление связанных списков

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

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    ОповеститьОбИзменении(Объект.Ссылка);
КонецПроцедуры

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

Разница с Оповестить() простая:

  • ОповеститьОбИзменении() — про данные: «объект такого-то типа изменился, обновите связанные списки». Реагирует платформа.
  • Оповестить() — про логику: «произошло вот такое событие», а что с ним делать, решает ваш код в ОбработкаОповещения.

В типовых конфигурациях (БП 3.0, ЗУП 3.1, УТ 11) стандартные формы уже вызывают ОповеститьОбИзменении при записи, поэтому списки обновляются «сами собой». Дописывать его приходится в собственных обработках и доработках.

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

Обновление окна по таймеру

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

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

Обработчик ожидания. Когда обновлять надо по своей логике, подключите клиентский обработчик ожидания:

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ПодключитьОбработчикОжидания("ОбновитьПоТаймеру", 60);
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьПоТаймеру()
    Элементы.Список.Обновить();
КонецПроцедуры

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

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

Какой метод выбрать: сводная таблица

Что нужно обновитьМетодГде вызывать
Строки динамического спискаЭлементы.Список.Обновить()клиент
Данные объекта формы из базыПрочитать() (теряет правки)клиент
Внешний вид, условное оформлениеОбновитьОтображениеДанных()клиент
Обновить другую открытую формуОповестить() + ОбработкаОповещенияклиент
Обновить списки по факту записиОповеститьОбИзменении()клиент/сервер
Периодически по таймеруПодключитьОбработчикОжидания()клиент
Вручную пользователемкоманда Обновить / F5—

Общее правило: обновляйте точечно. Если изменился один список — обновите один список, а не всю форму.

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

Обновление окна — это запросы к серверу и СУБД. Лишние вызовы напрямую бьют по скорости.

  • ⚠️ Короткий период автообновления. Период в 1–5 секунд на списке, который видят десятки пользователей, создаёт поток однотипных запросов к базе. Для оперативных журналов ставьте 30–60 секунд и больше — секундная свежесть почти никогда не нужна.
  • ⚠️ ОбновитьОтображениеДанных() на тяжёлой форме. Метод пересчитывает всё условное оформление. На форме с большим табличным полем и множеством правил оформления частый вызов заметно подтормаживает. Вызывайте его по факту изменения, а не в каждом обработчике.
  • ⚠️ Полное перечитывание вместо точечного. Прочитать() ради обновления одного реквизита — перебор: он идёт за всем объектом и теряет несохранённые правки. Чаще достаточно обновить список или перерисовать форму.

Типичные ошибки, из-за которых окно «не обновляется»:

  1. Оповестить() вызвали на сервере. Метод клиентский. В серверной процедуре он не сработает — выносите вызов в клиентский контекст.
  2. Не совпали имена события. В Оповестить() одно написание, в ОбработкаОповещения — другое. Сигнал уходит, но условие не срабатывает.
  3. Нет обработчика ОбработкаОповещения. Оповещение рассылается, но принимающая форма его не слушает — реакции ноль.
  4. Путают методы. ОбновитьОтображениеДанных() не читает объект из базы заново, а Прочитать() не перечитывает динамический список. Для списка — только Обновить().
  5. Рекурсия в обработчике. Если ОбработкаОповещения сама вызывает Оповестить() с тем же именем события, формы будут бесконечно будить друг друга.
Чем `Оповестить` отличается от `ОповеститьОбИзменении`?
ОповеститьОбИзменении — про данные: сообщает платформе, что объект изменился, и связанные динамические списки обновляются сами. Оповестить — про событие: шлёт сигнал с произвольным именем, а реакцию вы пишете вручную в ОбработкаОповещения.
Почему не срабатывает `ОбработкаОповещения`?
Три частые причины: Оповестить() вызван на сервере (метод клиентский), имя события в вызове и в обработчике написаны по-разному, либо на форме вообще нет процедуры ОбработкаОповещения.
Как обновить список после записи элемента из другой формы?
В форме-источнике после записи вызовите Оповестить("ИмяСобытия", Объект.Ссылка), а в форме со списком в ОбработкаОповещения поймайте это событие и вызовите Элементы.Список.Обновить(). Либо используйте ОповеститьОбИзменении(Объект.Ссылка) — тогда ручной обработчик не нужен.
Можно ли обновлять окно автоматически по времени?
Да. Для динамического списка задайте период обновления в свойствах элемента. Для своей логики подключите клиентский обработчик ожидания методом ПодключитьОбработчикОжидания с интервалом в секундах.
Как пользователю обновить окно вручную?
Нажать F5 или команду Обновить в командной панели списка — она перечитает динамический список с актуальными данными.