Как программно закрыть форму 1С только после успешного выполнения записи

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Анализ проблемы: почему нельзя просто вызвать закрытие

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


Процедура КомандаЗаписатьИЗакрыть(Кнопка)
    ОсновныеДействияФормыЗаписать(Кнопка); // Вызов записи
    ЭтаФорма.Закрыть(); // Форма закроется в любом случае? Не всегда.
КонецПроцедуры

В управляемом приложении, если метод Записать() вызывает исключение (ошибку валидации), выполнение кода прерывается, и до строки Закрыть() управление не доходит. Однако в обычных формах или при использовании оберток-процедур логика может работать иначе. Выясним, как сделать это максимально надежно.

Решение для обычных форм (v8.2 и v8.3 в режиме обычного приложения)

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


Процедура КнопкаЗаписатьИЗакрытьНажатие(Кнопка)
    // Метод Записать() вернет Истина, если объект успешно сохранен в БД
    Если ЭтаФорма.Записать() Тогда
        ЭтаФорма.Закрыть();
    Иначе
        // Если запись не удалась (например, из-за блокировки), 
        // сообщение об ошибке выведется платформой, а форма останется открытой.
        Сообщить("Не удалось записать объект, закрытие отменено.");
    КонецЕсли;
КонецПроцедуры

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

Решение для управляемых форм (v8.3)

В управляемых формах ситуация иная. Метод Записать() на клиенте не возвращает результат. Здесь мы должны использовать событийную модель. Разберем по шагам наиболее правильный подход.

1. Использование стандартной команды

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

2. Программный вызов с проверкой

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


&НаКлиенте
Процедура ЗаписатьИЗакрытьНастраиваемая(Команда)
    
    // Параметры записи позволяют тонко настроить процесс
    ПараметрыЗаписи = Новый Структура;
    
    Попытка
        // Если запись не удастся, выполнение перейдет в блок Исключение
        Если Записать(ПараметрыЗаписи) Тогда
            Закрыть();
        КонецЕсли;
    Исключение
        // Обработка ошибки, если нужно (например, логирование)
        ТекстОшибки = КраткоеОписаниеОшибки(ИнформацияОбОшибке());
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка при сохранении: " + ТекстОшибки);
    КонецПопытки;
    
КонецПроцедуры

3. Использование события «ПослеЗаписи»

Это самый надежный метод, если логика закрытия должна срабатывать всегда после успешного сохранения, независимо от того, как была инициирована запись. Мы можем установить флаг «ЗакрытьПослеЗаписи» в ДополнительныеСвойства или в переменную модуля формы.


&НаКлиенте
Перем ЗакрытьПослеУспешнойЗаписи;

&НаКлиенте
Процедура КомандаЗаписатьИЗакрыть(Команда)
    ЗакрытьПослеУспешнойЗаписи = Истина;
    Записать();
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    Если ЗакрытьПослеУспешнойЗаписи = Истина Тогда
        Закрыть();
    КонецЕсли;
КонецПроцедуры

Оптимизация: проверка модифицированности

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


&НаКлиенте
Процедура ОптимизированноеЗакрытие(Команда)
    // Если данные не менялись, просто закрываем форму без обращения к серверу
    Если Не ЭтаФорма.Модифицированность Тогда
        Закрыть();
        Возврат;
    КонецЕсли;
    
    // Если изменения есть — записываем
    Если Записать() Тогда
        Закрыть();
    КонецЕсли;
КонецПроцедуры

Внимание: Будьте осторожны с методом Модифицированность. В некоторых конфигурациях (например, ERP или УТ 11) модифицированность может устанавливаться программно при открытии, что приведет к ложному срабатыванию записи. Всегда проверяйте логику заполнения объекта.

Итоги и рекомендации

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

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

Разбор этих механизмов позволяет создавать отказоустойчивые интерфейсы, которые ведут себя предсказуемо для пользователя и не допускают потери данных или закрытия пустых окон при возникновении ошибок в бизнес-логике системы.

← На главную