Как при закрытии документа сохранить данные без открытия окна с подтверждением в 1С?

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

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

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

Понимание проблемы: почему возникает окно подтверждения?

Прежде чем перейти к решениям, выясним причину появления диалогового окна. Платформа 1С отслеживает изменения, внесенные в данные формы. Если после открытия формы были сделаны какие-либо изменения (например, введены новые значения в поля, добавлены строки в табличные части), то свойство формы Модифицированность автоматически устанавливается в значение Истина. При попытке закрыть такую "модифицированную" форму платформа предполагает, что пользователь мог забыть сохранить свои изменения, и предлагает это сделать, выводя соответствующий диалог.

Наша задача — сделать так, чтобы перед закрытием формы платформа считала, что все изменения уже сохранены, то есть установить свойство Модифицированность в Ложь, либо перехватить стандартную обработку закрытия и выполнить свои действия.

Решение 1: Программная запись и снятие модифицированности

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

Шаг 1: Программная запись объекта

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

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

Синтаксис метода Записать():

Записать(<ПараметрыЗаписи>)

где <ПараметрыЗаписи> — необязательная структура, позволяющая передать дополнительные параметры в обработчики событий записи. Например:


СтруктураПараметровЗаписи = Новый Структура;
СтруктураПараметровЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Запись); // Просто запись, без проведения
Записать(СтруктураПараметровЗаписи);

Возвращаемое значение: Метод Записать() возвращает булево значение: Истина, если запись прошла успешно, и Ложь в противном случае. Это позволяет нам проверить результат операции записи.

Шаг 2: Снятие флага модифицированности

После того как объект успешно записан, нам необходимо явно указать платформе, что форма больше не содержит несохраненных изменений. Для этого мы устанавливаем свойство формы Модифицированность в значение Ложь.

Модифицированность = Ложь;

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

Шаг 3: Закрытие формы

Наконец, после успешной записи и снятия флага модифицированности, мы можем безопасно закрыть форму, вызвав стандартный метод Закрыть().

Закрыть();

Пример кода для комплексного решения:

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


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

Этот подход является наиболее предпочтительным, так как он использует стандартные механизмы платформы для записи объекта и контролирует его состояние.

Решение 2: Перехват события "ПередЗакрытием"

Альтернативным способом управления процессом сохранения является перехват события формы ПередЗакрытием. Этот обработчик вызывается платформой непосредственно перед закрытием формы и позволяет нам вмешаться в стандартный процесс.

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

Пример кода для обработчика ПередЗакрытием:


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

Важный момент здесь — параметр СтандартнаяОбработка. Установка его в Ложь означает, что платформа не будет выполнять свои стандартные действия по закрытию модифицированной формы, а передаст управление нам. Если мы хотим полностью отменить закрытие (например, из-за ошибки сохранения), мы устанавливаем параметр Отказ в Истина.

Ключевые нюансы и возможные сложности

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

Данные формы и объект базы данных

Когда вы открываете форму документа (например, Документ.Отпуск.ФормаОбъекта), платформа создает объект формы, который содержит реквизиты, отображаемые на экране. Эти реквизиты формы могут быть напрямую связаны с реквизитами объекта базы данных (основной реквизит формы, обычно называемый Объект) или быть независимыми. Если вы заполняете форму, то данные сначала попадают в реквизиты формы.

При вызове стандартной команды "Записать" или метода Записать() платформа автоматически переносит данные из реквизитов формы в реквизиты основного объекта, связанного с формой, перед тем как передать этот объект на сервер для сохранения в базу данных.

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

Если вы открываете форму и заполняете ее извне, а затем хотите записать, то самый простой путь — это вызов метода Записать() формы. Платформа сама позаботится о переносе данных. Если же по какой-то причине вам нужно получить данные формы и вручную заполнить объект, используйте метод ДанныеФормыВЗначение().

Использование метода ДанныеФормыВЗначение()

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


&НаКлиенте
Процедура ПолучитьДанныеИЗаписатьОбъект()
    // Получаем текущие данные формы в виде объекта документа
    ОбъектДокумента = ДанныеФормыВЗначение(ЭтотОбъект, Тип("ДокументОбъект." + ИмяДокументаОтпуск(ТекущиеДанные.ВидДокументаОтпуск)));

    // Здесь можно программно изменить ОбъектДокумента, если требуется
    // ...

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

Этот подход дает нам больше контроля над объектом перед записью, но требует явного переноса данных и вызова метода Записать() уже у самого объекта, а не у формы. При этом, если вы работаете в контексте управляемой формы, метод Записать() формы (как в Решении 1) часто является более простым и достаточным, поскольку он включает в себя логику переноса данных.

Автоматическое заполнение и запись извне

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

В вызывающем коде:


&НаКлиенте
Процедура ОткрытьИЗаписатьДокумент()
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("АвтоматическиЗаписатьИЗакрыть", Истина);
    // Добавляем другие параметры для заполнения формы, если необходимо
    // ...

    ОткрытьФорму("Документ." + ИмяДокументаОтпуск(ТекущиеДанные.ВидДокументаОтпуск) + ".ФормаОбъекта", ПараметрыОткрытия, ЭтаФорма);
КонецПроцедуры

В открываемой форме (например, в обработчике ПриСозданииНаСервере или ПослеОткрытия):


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

&НаКлиенте
Процедура ЗаписатьИЗакрытьФормуНаКлиенте()
    Если Записать() Тогда
        Модифицированность = Ложь;
        Закрыть();
    Иначе
        Сообщить("Автоматическое сохранение не удалось.");
    КонецЕсли;
КонецПроцедуры

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

Важность обработки ошибок

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

Заключение

Автоматическое сохранение данных при закрытии формы без диалогового окна — это распространенная задача, которая имеет надежные решения на платформе 1С:Предприятие 8.3. Мы рассмотрели два основных подхода:

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

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

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

← На главную