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