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