Программное создание динамического списка или таблицы значений на управляемой форме 1С делается в два шага: сначала на сервере добавляются реквизиты формы методом ИзменитьРеквизиты, затем для них создаются элементы ТаблицаФормы и ПолеФормы через Элементы.Добавить. У таблицы значений каждая колонка — отдельный реквизит с путём к реквизиту-таблице. У динамического списка задаются текст запроса, основная таблица и параметры, а отборы, сортировка и условное оформление настраиваются через его собственные коллекции.
Так дорабатывают типовые формы из расширений и общих модулей: визуально форма не меняется, обновления конфигурации проходят без конфликтов. Ниже — рабочий код для обоих случаев, с оформлением и обновлением параметров.
Когда формы меняют программно
Программная модификация формы оправдана, когда:
- вы дорабатываете типовую форму и не хотите снимать её с поддержки или конфликтовать в расширении с визуальными правками;
- состав колонок зависит от данных (например, по колонке на каждый вид цены);
- одна и та же вставка нужна в нескольких формах — её удобно оформить общей процедурой.
Порядок действий всегда один:
- В
ПриСозданииНаСервередобавить реквизиты (ИзменитьРеквизиты). - Создать элементы и связать их с реквизитами через
ПутьКДанным. - Назначить обработчики событий через
УстановитьДействие. - Добавить условное оформление.

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




