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