Как сохранить изменения в управляемой форме 1С перед печатью или передачей ссылки

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

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

Суть проблемы: данные формы vs данные базы данных

Рассмотрим стандартный сценарий: в управляемой форме есть дерево значений или таблица, данные из которых программно переносятся в табличную часть Объект.Товары или Объект.РеквизитыДоговора. Программист видит изменения на экране, но при вызове функции печати, куда передается Объект.Ссылка, в печатной форме отображаются старые данные.

Выясним причину этого поведения. В управляемых формах переменная Объект имеет тип ДанныеФормыСтруктура. Это временная копия данных, которая живет в оперативной памяти сервера (и частично клиента). Ссылка же (Объект.Ссылка) — это уникальный идентификатор записи, которая уже физически существует в таблицах базы данных (SQL или файловой). Пока вы не «сбросили» изменения из оперативной памяти в базу, по ссылке всегда будут считываться старые значения.

Типичные ошибки при сохранении

Проанализируем ошибки, которые часто допускаются в попытках решить эту задачу:

  1. Использование конструкции Объект.Ссылка.ПолучитьОбъект().Записать(). Это крайне опасный метод в контексте формы. Вызывая ПолучитьОбъект(), вы создаете в памяти еще одну независимую копию документа. Если вы запишете ее, а потом пользователь попытается сохранить саму форму, система выдаст ошибку: «Данные были изменены или удалены другим пользователем». Кроме того, изменения, внесенные пользователем вручную в другие поля формы, могут не попасть в этот «параллельный» объект.
  2. Попытка вызвать Объект.Записать(). У типа ДанныеФормыСтруктура нет метода Записать(). Это вызывает ошибку выполнения.
  3. Использование ЭтотОбъект. В модуле управляемой формы ключевое слово ЭтотОбъект не определено. Для обращения к самой форме используется ЭтаФорма, но чаще всего методы формы вызываются напрямую.

Правильное сохранение данных через методы формы

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

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


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

Запись документа без проведения

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

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


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

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

Работа с контекстом: ЭтаФорма и ЭтотОбъект

Разберем подробнее, почему возникают путаницы в терминах. В 1С существует несколько уровней объектов:

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

Алгоритм подготовки данных перед печатью

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

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

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


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

    // 2. Теперь вызываем внешнюю обработку печати
    ОбработкаПечати = Обработки.рбсПечатьMicrosoftWord.Создать();
    ОбработкаПечати.Объект = Объект.Ссылка; // Теперь ссылка актуальна!
    ОбработкаПечати.рбсПечать();
    
КонецФункции

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

← На главную