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