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

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

1С: как программно закрыть управляемую форму

Как программно закрыть управляемую форму в 1С: метод Закрыть(), отказ от закрытия, закрытие из другой формы и из кода. Примеры кода, типичные ошибки и FAQ.

В управляемом приложении 1С форма закрывается либо пользователем (кнопкой «Закрыть», крестиком, Esc), либо программно — вызовом метода Закрыть() в коде формы или извне. Программное закрытие требуется после успешного сохранения данных, при отмене диалога, при перенаправлении пользователя на другую форму и в десятках других сценариев.

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

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

Базовый способ: метод Закрыть() в клиентском коде формы

Самый простой сценарий — закрыть форму из её собственного обработчика команды. Метод Закрыть() вызывается только в клиентских процедурах (директивы &НаКлиенте, &НаКлиентеНаСервереБезКонтекста не подойдут — там форма как объект недоступна в полном объёме для закрытия).

&НаКлиенте

Процедура СохранитьИЗакрыть(Команда)

Если ПроверитьИЗаписатьДанные() Тогда

Закрыть();

КонецЕсли;

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

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

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

&НаКлиенте

Процедура Выбрать(Команда)

Закрыть(ВыбранноеЗначение);

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

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

Закрытие с проверкой: обработчики ПередЗакрытием и ПриЗакрытии

Закрытие управляемой формы — не мгновенная операция, а событие с возможностью отмены. Платформа сначала вызывает ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка). Установка Отказ = Истина отменяет закрытие — и это работает как для действий пользователя, так и для программного вызова Закрыть().

&НаКлиенте

Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)

Если Модифицированность И НЕ ЗавершениеРаботы Тогда

Отказ = Истина;

ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВопросаОСохранении", ЭтотОбъект);

ПоказатьВопрос(ОписаниеОповещения, "Данные изменены. Сохранить?", РежимДиалогаВопрос.ДаНетОтмена);

КонецЕсли;

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

Обратите внимание на параметр ЗавершениеРаботы: при завершении сеанса нельзя показывать модальные и асинхронные диалоги — платформа просто не даст их отобразить. Если требуется предупредить пользователя, заполните ТекстПредупреждения и установите Отказ = Истина: платформа покажет форму в списке незакрытых окон.

Обработчик ПриЗакрытии(ЗавершениеРаботы) вызывается, когда отказ уже невозможен. В нём освобождают ресурсы: отключают обработчики ожидания, закрывают вспомогательные объекты, оповещают другие формы о закрытии. Писать в нём бизнес-логику с диалогами нельзя.

Закрытие формы после серверного вызова

Типовая ошибка новичков — попытаться закрыть форму в серверной процедуре после записи объекта. На сервере объект формы существует как данные, но метод Закрыть() там недоступен: закрытие — это операция клиентского интерфейса.

Правильный паттерн: серверная процедура выполняет запись и возвращает результат, а клиент решает, закрывать форму или нет.

&НаКлиенте

Процедура ЗаписатьИЗакрыть(Команда)

РезультатЗаписи = ЗаписатьНаСервере();

Если РезультатЗаписи.Успех Тогда

Закрыть();

Иначе

ПоказатьПредупреждение(, РезультатЗаписи.ТекстОшибки);

КонецЕсли;

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

&НаСервере

Функция ЗаписатьНаСервере()

Результат = Новый Структура("Успех, ТекстОшибки", Ложь, "");

Попытка

Записать(); // запись объекта формы

Результат.Успех = Истина;

Исключение

Результат.ТекстОшибки = ОписаниеОшибки();

КонецПопытки;

Возврат Результат;

КонецФункции

Такой подход дополнительно даёт контроль: если запись не удалась, форма остаётся открытой, и пользователь видит введённые данные и текст ошибки. Закрытие без проверки результата записи — прямой путь к потере введённых данных.

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

Закрытие формы из другой формы или общего модуля

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

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

// В закрываемой форме

&НаКлиенте

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

Если ИмяСобытия = "ЗакрытьФормуПодбора" Тогда

Закрыть();

КонецЕсли;

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

// В коде, инициирующем закрытие

Оповестить("ЗакрытьФормуПодбора");

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

Поиск открытой формы по уникальному идентификатору

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

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

Закрытие форм, открытых модально и с ожиданием результата

Формы, открытые через ОткрытьФорму() с переданным ОписаниеОповещения, рассчитаны на возврат значения. Закрытие такой формы через Закрыть(Результат) вызовет указанный обработчик, и в параметр Результат попадёт переданное значение. Если пользователь закрыл форму крестиком, в обработчик придёт Неопределено — это нужно обрабатывать.

&НаКлиенте

Процедура ОткрытьПодбор(Команда)

Оповещение = Новый ОписаниеОповещения("ПослеВыбораВПодборе", ЭтотОбъект);

ОткрытьФорму("Справочник.Номенклатура.Форма.ФормаПодбора", , ЭтотОбъект, , , , Оповещение);

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

&НаКлиенте

Процедура ПослеВыбораВПодборе(Результат, ДопПараметры) Экспорт

Если Результат = Неопределено Тогда

Возврат; // форму закрыли без выбора

КонецЕсли;

// обработка выбранного значения

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

Устаревший метод ОткрытьМодально() в современных конфигурациях не используется: режим совместимости интерфейса «Такси» и веб-клиент его не поддерживают. Если встретите его в старом коде — рефакторинг на ОткрытьФорму() с оповещением обязателен, иначе закрытие формы не вернёт результат корректно.

Сравнение вариантов закрытия

Закрыть() из кода самой формы

Подходит для кнопок «ОК», «Отмена», «Записать и закрыть». Ограничение — только клиентский контекст, закрытие может быть отменено в ПередЗакрытием

Закрыть(Результат) для форм-диалогов

Подходит для форм выбора и подбора, открытых с ОписаниемОповещения. Обязательно обрабатывайте Неопределено при закрытии крестиком

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

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

Прямой вызов через сохранённую ссылку на форму

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

Проверка результата и отладка закрытия

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

Если форма «не закрывается» программно, почти всегда причина в обработчике ПередЗакрытием, который устанавливает Отказ = Истина — отладчиком проверьте, доходит ли выполнение до этой ветки. Вторая частая причина — вызов Закрыть() в серверном контексте, где он просто недоступен, либо в модуле, где имя Закрыть не разрешается в метод формы.

Полезный приём при отладке — временно вывести в ПриЗакрытии сообщение или запись в журнал регистрации. Так вы убедитесь, что закрытие реально произошло, а не было отменено молча.

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

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

Вызов Закрыть() из клиентского обработчика
Норма

Форма закрывается, обработчик ПриЗакрытии отрабатывает

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

Ошибка «Метод недоступен» — вызов идёт в серверном контексте

Закрытие формы выбора с результатом
Норма

В обработчик оповещения приходит переданное значение

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

Приходит Неопределено — форму закрыли крестиком или Закрыть() вызван без параметра

Закрытие при несохранённых изменениях
Норма

Появляется вопрос о сохранении, отмена оставляет форму открытой

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

Форма закрывается молча, данные теряются — нет проверки Модифицированности в ПередЗакрытием

Закрытие из другой формы через оповещение
Норма

Целевая форма получает событие и закрывается

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

Ничего не происходит — имя события не совпадает или обработчик не реализован

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

Можно ли закрыть управляемую форму на сервере?

Нет. Метод Закрыть() доступен только в клиентском контексте, потому что закрытие — операция интерфейса. Серверная процедура должна вернуть признак результата, а клиентский код по этому признаку вызывает Закрыть().

Почему Закрыть() вызывается, но форма остаётся открытой?

Закрытие отменено в обработчике ПередЗакрытием установкой Отказ = Истина. Часто это проверка модифицированности или незавершённый асинхронный диалог. Пройдите отладчиком обработчик ПередЗакрытием и проверьте условия отказа.

Как закрыть форму без вопроса о сохранении изменений?

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

Как закрыть все открытые формы определённого вида?

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

Что попадёт в обработчик оповещения, если форму закрыли крестиком?

Придёт Неопределено. Поэтому в обработчике результата всегда первой строкой проверяйте Результат = Неопределено и прерывайте выполнение, иначе последующая логика отработает с пустым значением и может создать некорректные данные.

Можно ли запретить закрытие формы крестиком?

Полностью скрыть крестик у самостоятельного окна нельзя, но можно перехватить закрытие в ПередЗакрытием и установить Отказ = Истина по своему условию. Учитывайте параметр ЗавершениеРаботы: при завершении сеанса блокировать закрытие диалогами нельзя, только через ТекстПредупреждения.

Итог

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

Управляемая форма закрывается методом Закрыть() только в клиентском коде; для форм-диалогов результат передаётся параметром. Закрытие можно отменить в ПередЗакрытием, поэтому программный вызов не гарантирует закрытие. Из другой формы закрывайте через оповещения, а после серверной записи решение о закрытии принимайте на клиенте по результату.