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