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

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

Как отменить закрытие формы в 1С

Как отменить закрытие формы в 1С: обработчики ПередЗакрытием и ПриЗакрытии, параметр Отказ, проверка модифицированности, примеры кода для управляемых и обычных форм.

Закрытие формы в 1С можно перехватить и отменить программно — это стандартный механизм платформы, а не обходной приём. Для этого в модуле формы используется обработчик события ПередЗакрытием, в котором параметру Отказ присваивается значение Истина. Пока этот параметр равен Истина, форма останется открытой независимо от того, как пользователь попытался её закрыть: крестиком, клавишей Esc или командой.

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

Материал охватывает управляемые формы (режим «такси» и интерфейс 8.2/8.3) и отдельно — обычные формы, где синтаксис обработчиков отличается. Также разобраны ситуации, когда форма закрывается вопреки установленному отказу, и способы это диагностировать.

Как платформа обрабатывает закрытие формы

При попытке закрыть форму платформа вызывает цепочку событий. Сначала — ПередЗакрытием: именно здесь разработчик может остановить процесс. Затем, если отказа не произошло, выполняется ПриЗакрытии — это уведомление о том, что форма уже закрывается, и отменить закрытие в нём нельзя. Разница принципиальна: код очистки ресурсов пишут в ПриЗакрытии, а код проверок и отказов — только в ПередЗакрытием.

В управляемых формах обработчик ПередЗакрытием имеет параметры Отказ, ЗавершениеРаботы, ТекстПредупреждения и СтандартнаяОбработка. Параметр ЗавершениеРаботы сообщает, что закрытие происходит из-за завершения работы всей программы — в этом случае задавать вопросы пользователю нельзя, можно только заполнить ТекстПредупреждения и отказать.

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

Минимальный код отмены закрытия в управляемой форме

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

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

bsl
&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
	Если РаботаВыполняется Тогда
		Отказ = Истина;
	КонецЕсли;
КонецПроцедуры

Проверка результата проста: запустите форму в режиме предприятия, выполните условие блокировки и попробуйте закрыть окно всеми способами — крестиком, Esc, через «Файл → Закрыть». Форма должна оставаться открытой. Если она закрывается, обработчик либо не привязан к событию, либо условие не выполняется — проверьте это отладчиком, поставив точку останова внутри процедуры.

Отмена закрытия с вопросом пользователю

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

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

bsl
&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
	Если ЗавершениеРаботы Тогда
		Возврат;
	КонецЕсли;
	Если Модифицированность И Не ЗакрытиеПодтверждено Тогда
		Отказ = Истина;
		ОписаниеОповещения = Новый ОписаниеОповещения("ПередЗакрытиемЗавершение", ЭтотОбъект);
		ПоказатьВопрос(ОписаниеОповещения, "Данные изменены. Закрыть без сохранения?", РежимДиалогаВопрос.ДаНет);
	КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПередЗакрытиемЗавершение(Результат, ДопПараметры) Экспорт
	Если Результат = КодВозвратаДиалога.Да Тогда
		ЗакрытиеПодтверждено = Истина;
		Закрыть();
	КонецЕсли;
КонецПроцедуры

Штатная модифицированность и когда свой код не нужен

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

Собственная обработка оправдана, когда проверяется нечто большее, чем модифицированность: заполненность конкретных реквизитов, состояние связанных объектов, активная длительная операция, несогласованные данные в табличной части. Там платформа ничего не знает о прикладных правилах, и отказ от закрытия — корректное решение.

Способы удержать форму открытой

Штатная модифицированность

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

ПередЗакрытием с Отказ = Истина

Универсальный способ для любых проверок. Требует аккуратной обработки повторного закрытия и завершения работы.

Режим открытия окна БлокироватьВесьИнтерфейс

Не отменяет закрытие, но ограничивает сценарии: пользователь работает только с этой формой. Не заменяет проверку ПередЗакрытием.

Особенности обычных форм

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

Типовой фрагмент выглядит так: если форма модифицирована и пользователь на вопрос «Закрыть без сохранения?» ответил «Нет», то Отказ = Истина. Учтите, что обычные формы не поддерживаются в веб-клиенте и тонком клиенте управляемого приложения; если конфигурация переводится на управляемый интерфейс, код придётся переписывать в асинхронном стиле.

Типичные ошибки и диагностика проблем

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

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

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

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

Закрытие крестиком и Esc при активной блокировке
Норма

Форма остаётся открытой, данные на месте

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

Форма закрывается — обработчик не вызывается или условие не срабатывает

Повторное закрытие после ответа «Да» в вопросе
Норма

Форма закрывается один раз, без повторного вопроса

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

Вопрос появляется снова — не установлен признак подтверждения

Завершение работы программы целиком
Норма

Либо корректное закрытие, либо предупреждение через ТекстПредупреждения

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

Ошибка выполнения или зависший диалог

Проверка результата и границы применения

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

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

Итог

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

Закрытие формы отменяется только в обработчике ПередЗакрытием установкой Отказ = Истина; в ПриЗакрытии отказ невозможен. Для вопросов в управляемой форме используйте ПоказатьВопрос с оповещением и флаг подтверждения, при завершении работы программы диалоги не показывайте. Сначала проверьте, не решает ли задачу штатная модифицированность.

Частые вопросы

Можно ли отменить закрытие формы в обработчике ПриЗакрытии?

Нет. ПриЗакрытии вызывается, когда решение о закрытии уже принято, и параметра Отказ у него нет. Этот обработчик предназначен для освобождения ресурсов и уведомления других форм. Все проверки и отказы размещайте только в ПередЗакрытием.

Почему форма закрывается, хотя в ПередЗакрытием стоит Отказ = Истина?

Чаще всего обработчик не привязан к событию формы — проверьте в конфигураторе, что в свойствах формы у события «ПередЗакрытием» указана ваша процедура. Также убедитесь, что условие, при котором ставится отказ, действительно выполняется, и что дальше по коду Отказ не сбрасывается обратно в Ложь.

Как задать вопрос пользователю при закрытии в управляемой форме?

Сразу установите Отказ = Истина, затем вызовите ПоказатьВопрос с описанием оповещения. В процедуре-обработчике ответа, если пользователь подтвердил закрытие, установите признак подтверждения (реквизит формы) и вызовите Закрыть() — при повторном входе в ПередЗакрытием проверка признака пропустит закрытие.

Что делать с закрытием при завершении работы программы?

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

Нужен ли свой код, если требуется просто не потерять несохранённые данные?

Обычно нет. Управляемая форма объекта при изменении данных сама устанавливает модифицированность, и платформа при закрытии задаёт вопрос о сохранении. Собственный обработчик оправдан, только когда нужны дополнительные прикладные проверки, которых платформа не выполняет.

Отличается ли код для обычных форм?

Да. В обычных формах обработчик ПередЗакрытием имеет параметры Отказ и СтандартнаяОбработка, директивы &НаКлиенте не используются, а вопрос задаётся синхронно функцией Вопрос() — код короче, оповещения и флаг повторного входа не нужны. Однако обычные формы не работают в веб-клиенте и современном управляемом интерфейсе.