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