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