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