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