При переводе старых обработок с обычных форм на управляемые разработчики часто сталкиваются с фундаментальными различиями в архитектуре платформы. В обычных формах весь код выполнялся в едином толстом клиенте: можно было напрямую вызвать экспортную функцию модуля объекта, получить ТаблицаЗначений, присвоить ее табличному полю и вызвать простой метод СоздатьКолонки(). В управляемом интерфейсе действуют жесткие ограничения клиент-серверного взаимодействия и типизации данных формы. Разберем по шагам, как правильно перенести подобный механизм на управляемые формы.
Проанализируем основные архитектурные препятствия, возникающие при миграции кода:
ТаблицаЗначений или создавать COM-объекты вроде ADODB.Command для внешних баз данных. Все операции выборки и трансформации данных должны выполняться на сервере.Объект на управляемой форме не является самим объектом типа ОбработкаОбъект или ДокументОбъект. Это специальная интерфейсная проекция — ДанныеФормыСтруктура. Чтобы вызвать экспортный метод модуля объекта, необходимо явно преобразовать реквизит формы в прикладной объект.СоздатьКолонки() в управляемых формах нет. Если состав колонок неизвестен заранее и формируется на лету по данным внешнего SQL-запроса, требуется программно модифицировать структуру формы с помощью метода ИзменитьРеквизиты() и создавать элементы интерфейса через коллекцию Элементы.Рассмотрим, как связать модуль формы и модуль объекта. Если логику подключения к внешней базе данных и выборки через ADO решено оставить в модуле объекта, ее нельзя вызвать на форме напрямую. Выясним причину: контекст формы не видит методы объекта без предварительной инициализации.
Для обращения к экспортным методам объекта на сервере управляемой формы используется функция РеквизитФормыВЗначение(). Посмотрим на типовой пример реализации:
&НаСервере
Функция ПолучитьТаблицуИзОбъекта()
// Преобразуем реквизит формы в реальный объект внешней обработки
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Вызываем экспортную функцию, возвращающую ТаблицуЗначений
Возврат ОбработкаОбъект.ИзТКС();
КонецФункции
Также разработчик может вовсе отказаться от вызова модуля объекта, перенеся саму функцию выборки данных непосредственно в модуль формы с директивой &НаСервере или вынеся ее в общий модуль / модуль менеджера.
Поскольку состав колонок из внешней базы данных может динамически меняться, форму необходимо перестраивать программно. Разберем этот процесс подробно. Важно помнить: перед добавлением новых колонок следует обязательно удалить созданные ранее элементы и реквизиты, иначе при повторном формировании возникнет критическая ошибка дублирования имен.
Метод ИзменитьРеквизиты() является ресурсоемким, поэтому все операции удаления и добавления реквизитов мы должны выполнять за один системный вызов, передавая сформированные массивы. Посмотрим на полный пример процедуры построения таблицы на форме:
&НаСервере
Процедура ПерестроитьТаблицуФормы(ТаблицаИсточник)
ИмяТаблицыФормы = "ВременнаяТаблица1";
// 1. Очищаем ранее созданные элементы и реквизиты
РеквизитыДляУдаления = Новый Массив;
ЭлементТаблица = Элементы[ИмяТаблицыФормы];
Для Каждого КолонкаФормы Из ЭлементТаблица.ПодчиненныеЭлементы Цикл
// Формируем путь к удаляемому реквизиту формы
РеквизитыДляУдаления.Добавить(ИмяТаблицыФормы + "." + КолонкаФормы.Имя);
Элементы.Удалить(КолонкаФормы);
КонецЦикла;
Если РеквизитыДляУдаления.Количество() > 0 Тогда
ИзменитьРеквизиты(Новый Массив, РеквизитыДляУдаления);
КонецЕсли;
// 2. Создаем новые реквизиты колонок таблицы формы
РеквизитыДляДобавления = Новый Массив;
Для Каждого КолонкаИсточник Из ТаблицаИсточник.Колонки Цикл
НовыйРеквизит = Новый РеквизитФормы(
КолонкаИсточник.Имя,
КолонкаИсточник.ТипЗначения,
ИмяТаблицыФормы,
КолонкаИсточник.Заголовок
);
РеквизитыДляДобавления.Добавить(НовыйРеквизит);
КонецЦикла;
ИзменитьРеквизиты(РеквизитыДляДобавления);
// 3. Добавляем элементы интерфейса (колонки) в таблицу
Для Каждого КолонкаИсточник Из ТаблицаИсточник.Колонки Цикл
НовоеПоле = Элементы.Добавить(
КолонкаИсточник.Имя,
Тип("ПолеФормы"),
ЭлементТаблица
);
НовоеПоле.Вид = ВидПоляФормы.ПолеВвода;
НовоеПоле.ПутьКДанным = ИмяТаблицыФормы + "." + КолонкаИсточник.Имя;
КонецЦикла;
КонецПроцедуры
После того как структура реквизитов и колонок приведена в полное соответствие с источником, остается загрузить строки. В управляемых формах для заполнения коллекции формы из прикладного объекта ТаблицаЗначений применяется процедура ЗначениеВДанныеФормы().
Объединим вызовы в единую серверную процедуру и подключим ее к обработчику клиентской кнопки:
&НаСервере
Процедура СформироватьОстаткиНаСервере()
// Получаем прикладной объект и вызываем функцию выборки данных
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
ТаблицаДанных = ОбработкаОбъект.ИзТКС();
// Перестраиваем колонки под полученную выборку
ПерестроитьТаблицуФормы(ТаблицаДанных);
// Загружаем данные в реквизит формы
ЗначениеВДанныеФормы(ТаблицаДанных, ЭтаФорма.ВременнаяТаблица1);
КонецПроцедуры
&НаКлиенте
Процедура СфорОстат(Команда)
СформироватьОстаткиНаСервере();
КонецПроцедуры
Рассмотрим дополнительные технические нюансы, которые необходимо учитывать при миграции кода с использованием ADODB:
COMОбъект приведет к ошибке. В таких конфигурациях подключение к внешним базам следует реализовывать через стандартные Внешние источники данных 1С либо через вызов внешних HTTP-сервисов.ТабличныйДокумент. Вывод данных в ячейки отчета избавляет от необходимости сложного программного манипулирования реквизитами формы через ИзменитьРеквизиты().