В процессе разработки интерфейсов на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с проблемой «легкого» закрытия форм. Клавиша ESC является стандартным системным сочетанием для закрытия активного окна, но иногда это приводит к случайной потере данных, которые пользователь вводил в течение длительного времени. Рассмотрим подробнее, как мы можем программно контролировать этот процесс, разберем доступные штатные механизмы и проанализируем специфические обходные пути.
Прежде всего, проанализируем самый простой и заложенный платформой «из коробки» способ — использование признака модифицированности. 1С автоматически отслеживает изменения в данных, связанных с основным реквизитом формы. Если пользователь изменил значение в поле ввода, у формы взводится флаг Модифицированность.
В этом случае при попытке закрытия формы (в том числе по ESC) система сама выдаст стандартный вопрос: «Данные были изменены. Сохранить изменения?». Однако бывают ситуации, когда данные заполняются программно или через нестандартные элементы управления, и флаг не взводится автоматически. В таких случаях мы можем управлять им вручную.
Разберем пример кода, который принудительно помечает форму как измененную сразу после открытия или при начале редактирования:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Если мы хотим, чтобы вопрос задавался всегда, даже если пользователь ничего не трогал
ЭтаФорма.Модифицированность = Истина;
КонецПроцедуры
Этот метод хорош своей простотой, но он не дает возможности кастомизировать текст вопроса или выполнять специфические проверки перед закрытием.
Теперь рассмотрим ситуацию, когда нам нужно программно определить: закрывается ли форма штатной кнопкой «Записать и закрыть» или же пользователь нажал ESC (или «крестик»). Платформа 1С не передает напрямую код нажатой клавиши в обработчик закрытия, поэтому нам придется прибегнуть к логической хитрости с использованием переменной-флага.
Выясним причину, по которой это необходимо: нам нужно разрешить закрытие без лишних вопросов, если нажата кнопка сохранения, и заблокировать его с выдачей предупреждения, если инициировано системное закрытие.
Выполним следующие шаги:
РазрешеноЗакрытие.Истина.ПередЗакрытием будем проверять значение этого флага.Посмотрим на пример реализации:
&НаКлиенте
Перем РазрешеноЗакрытие;
&НаКлиенте
Процедура КомандаЗаписатьИЗакрыть(Команда)
// Устанавливаем флаг, так как это осознанное действие пользователя
РазрешеноЗакрытие = Истина;
ЭтаФорма.Закрыть();
КонецПроцедуры
&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
// Если флаг не установлен, значит нажали ESC или крестик
Если РазрешеноЗакрытие <> Истина Тогда
Отказ = Истина; // Прерываем закрытие
// Здесь мы можем вызвать свой диалог (см. следующий раздел про асинхронность)
ПоказатьВопросОбОтмене();
КонецЕсли;
КонецПроцедуры
Важно помнить, что в современных версиях платформы 1С 8.3 (особенно при работе в веб-клиенте или с отключенными модальными окнами) мы не можем просто остановить поток выполнения внутри ПередЗакрытием и ждать ответа пользователя. Если мы вызовем асинхронный вопрос, процедура завершится, и форма закроется до того, как пользователь нажмет «Да» или «Нет».
Проанализируем правильный паттерн работы с ОписаниеОповещения для решения нашей задачи:
&НаКлиенте
Процедура ПоказатьВопросОбОтмене()
Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопрос", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Вы действительно хотите закрыть форму без сохранения?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаНаВопрос(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// Если пользователь подтвердил закрытие, взводим флаг и закрываем форму программно
РазрешеноЗакрытие = Истина;
ЭтаФорма.Закрыть();
КонецЕсли;
КонецПроцедуры
В этом примере мы сначала всегда ставим Отказ = Истина в процедуре ПередЗакрытием, тем самым блокируя «автоматическое» закрытие по ESC. Затем мы задаем вопрос, и только в случае положительного ответа вызываем метод Закрыть() повторно, но уже с «разрешающим» флагом, чтобы избежать бесконечного цикла.
Как упоминалось в обсуждении, иногда стандартных средств 1С бывает недостаточно, особенно когда форма является частью сложной системы внешних обработок с динамическими полями. В таких случаях некоторые разработчики используют внешние компоненты (DLL) для низкоуровневого перехвата событий клавиатуры Windows (так называемые «хуки»).
Важный момент: Использование внешних DLL нарушает кроссплатформенность приложения. Ваш код перестанет работать в Linux-клиентах, в мобильном приложении или в браузере. Поэтому мы настоятельно рекомендуем придерживаться методики с флагом РазрешеноЗакрытие и обработкой события ПередЗакрытием, так как это решение будет работать на любой платформе, поддерживаемой 1С.
В редких случаях, когда логика закрытия конфликтует с другими событиями формы, можно применить «разрыв» потока через ПодключитьОбработчикОжидания. Это позволяет выполнить проверку состояния формы через доли секунды после того, как событие закрытия было инициировано, что иногда помогает избежать блокировок интерфейса при взаимодействии нескольких открытых окон.
Подведем итог: наиболее надежным и «чистым» способом защиты от случайного нажатия ESC является комбинация из:
ПередЗакрытием с параметром Отказ = Истина.ОписаниеОповещения для асинхронного подтверждения действия пользователем.Такой подход гарантирует сохранность данных и обеспечивает предсказуемое поведение интерфейса в соответствии со стандартами разработки на платформе 1С:Предприятие 8.3.