При разработке конфигураций на платформе 1С:Предприятие 8.3 с использованием управляемых форм, часто возникает необходимость динамического изменения интерфейса, например, программного добавления колонок в табличные части. Такая задача, казалось бы, проста, но может привести к неожиданным ошибкам, как в случае, когда мы добавляем колонки в несколько таблиц на одной форме. Рассмотрим подробнее ситуацию, когда при добавлении колонок во вторую таблицу возникает ошибка "Недопустимое значение параметра", и выясним причину такого поведения.
Представим, что у нас на форме есть две табличные части, допустим, ТаблицаЧасы и ТаблицаЧасыПлан, и мы хотим программно добавить в них колонки, основываясь на данных из справочника или какого-либо другого источника. Для этого мы используем обработчик события формы ПриСозданииНаСервере, который позволяет нам изменять структуру формы до ее отображения пользователю. В коде, который привел к ошибке, мы видим следующую логику:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// ... (инициализация периода и получение данных)
ТаблицаПодразделение = ЗаполнитьПодразделенияНаСервере();
НомерСтроки = 0;
Для Каждого СтрокаПодразделение Из ТаблицаПодразделение Цикл
НомерСтроки = НомерСтроки + 1;
НазваниеПодразделения = СтрокаПодразделение.Подразделение.Наименование;
НазваниеКолонки = "Подразделение"+Строка(НомерСтроки); // Генерируем имя колонки
Эл = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаЧасы);
Эл.Вид = ВидПоляФормы.ПолеВвода;
Эл.Заголовок = НазваниеПодразделения;
Эл.ПутьКДанным = "Объект.ТаблицаЧасы."+НазваниеКолонки;
КонецЦикла;
// Второй цикл для другой таблицы
НомерСтроки = 0; // Сброс счетчика
ТаблицаПодразделениеПлан = ЗаполнитьПодразделенияНаСервере();
Для Каждого СтрокаПодразделение Из ТаблицаПодразделениеПлан Цикл
НомерСтроки = НомерСтроки + 1;
НазваниеПодразделения = СтрокаПодразделение.Подразделение.Наименование;
НазваниеКолонки = "Подразделение"+Строка(НомерСтроки); // Снова генерируем имя колонки
ЭлПлан = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаЧасыПлан); // Здесь возникает ошибка
ЭлПлан.Вид = ВидПоляФормы.ПолеВвода;
ЭлПлан.Заголовок = НазваниеПодразделения;
ЭлПлан.ПутьКДанным = "Объект.ТаблицаЧасыПлан."+НазваниеКолонки;
КонецЦикла;
КонецПроцедуры
При выполнении этого кода мы сталкиваемся с ошибкой "Недопустимое значение параметра" во втором цикле. Интересно, что если закомментировать первый цикл, то второй выполняется без проблем. В чем же дело? Почему система ругается, когда мы пытаемся добавить элементы во вторую таблицу?
Разберем главный принцип работы с элементами формы в 1С:Предприятии. Каждый элемент формы, будь то поле ввода, кнопка, таблица или, как в нашем случае, динамически добавленное поле, должен иметь уникальный идентификатор (имя) в коллекции Элементы всей формы. Метод Элементы.Добавить() принимает три основных параметра:
Имя (строка): Уникальный идентификатор добавляемого элемента.Тип (Тип): Тип добавляемого элемента (например, Тип("ПолеФормы")).Родитель (ЭлементФормы): Родительский элемент, в который будет добавлен новый элемент в иерархии формы.Важно понимать, что параметр Родитель определяет только визуальное расположение элемента в структуре формы. А вот Имя должно быть уникальным в общей коллекции Элементы формы, а не только среди дочерних элементов указанного родителя.
В нашем исходном коде происходит следующее:
ТаблицаЧасы мы создаем колонки с именами "Подразделение1", "Подразделение2", "Подразделение3" и так далее. Эти имена добавляются в общую коллекцию Элементы формы.ТаблицаЧасыПлан мы снова обнуляем счетчик НомерСтроки = 0;. Это приводит к тому, что во втором цикле мы пытаемся создать элементы с теми же самыми именами: "Подразделение1", "Подразделение2", "Подразделение3", которые уже были добавлены в первом цикле.Система 1С обнаруживает попытку добавить элемент с уже существующим идентификатором и выдает ошибку "Недопустимое значение параметра", так как нарушается требование уникальности имен элементов формы.
Чтобы решить эту проблему, нам необходимо гарантировать уникальность имен всех динамически добавляемых элементов формы. Есть несколько подходов, которые мы можем применить:
Самый простой способ – использовать один общий счетчик, который не будет сбрасываться между циклами. Таким образом, каждая новая колонка, независимо от того, в какую таблицу она добавляется, получит уникальный номер.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Период = Дата('00010101') Тогда
Объект.Период = НачалоМесяца(ТекущаяДата());
КонецЕсли;
// Общий счетчик для всех динамически создаваемых элементов на форме
ОбщийНомерЭлемента = 0;
// Первый цикл для ТаблицаЧасы
ТаблицаПодразделение = ЗаполнитьПодразделенияНаСервере();
Для Каждого СтрокаПодразделение Из ТаблицаПодразделение Цикл
ОбщийНомерЭлемента = ОбщийНомерЭлемента + 1;
НазваниеПодразделения = СтрокаПодразделение.Подразделение.Наименование;
НазваниеКолонки = "КолонкаПодразделение" + Строка(ОбщийНомерЭлемента); // Уникальное имя
Эл = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаЧасы);
Эл.Вид = ВидПоляФормы.ПолеВвода;
Эл.Заголовок = НазваниеПодразделения;
Эл.ПутьКДанным = "Объект.ТаблицаЧасы." + НазваниеКолонки;
КонецЦикла;
// Второй цикл для ТаблицаЧасыПлан
// Счетчик ОбщийНомерЭлемента продолжает увеличиваться
ТаблицаПодразделениеПлан = ЗаполнитьПодразделенияНаСервере();
Для Каждого СтрокаПодразделение Из ТаблицаПодразделениеПлан Цикл
ОбщийНомерЭлемента = ОбщийНомерЭлемента + 1;
НазваниеПодразделения = СтрокаПодразделение.Подразделение.Наименование;
НазваниеКолонки = "КолонкаПодразделение" + Строка(ОбщийНомерЭлемента); // Уникальное имя
ЭлПлан = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаЧасыПлан);
ЭлПлан.Вид = ВидПоляФормы.ПолеВвода;
ЭлПлан.Заголовок = НазваниеПодразделения;
ЭлПлан.ПутьКДанным = "Объект.ТаблицаЧасыПлан." + НазваниеКолонки;
КонецЦикла;
КонецПроцедуры
В этом примере мы заменили НомерСтроки на ОбщийНомерЭлемента, который инкрементируется в каждом цикле и не сбрасывается. Таким образом, колонки получат имена вроде "КолонкаПодразделение1", "КолонкаПодразделение2", "КолонкаПодразделение3" (для первой таблицы), а затем "КолонкаПодразделение4", "КолонкаПодразделение5" и так далее (для второй таблицы), обеспечивая их уникальность.
Более наглядным и структурированным подходом является добавление префикса к имени колонки, который будет указывать на родительскую таблицу. Это делает код более читаемым и облегчает отладку, так как по имени колонки сразу понятно, к какой таблице она относится.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Период = Дата('00010101') Тогда
Объект.Период = НачалоМесяца(ТекущаяДата());
КонецЕсли;
ТаблицаПодразделение = ЗаполнитьПодразделенияНаСервере();
НомерСтроки = 0;
Для Каждого СтрокаПодразделение Из ТаблицаПодразделение Цикл
НомерСтроки = НомерСтроки + 1;
НазваниеПодразделения = СтрокаПодразделение.Подразделение.Наименование;
// Добавляем префикс "ТаблицаЧасы_" к имени колонки
НазваниеКолонки = "ТаблицаЧасы_Подразделение" + Строка(НомерСтроки);
Эл = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаЧасы);
Эл.Вид = ВидПоляФормы.ПолеВвода;
Эл.Заголовок = НазваниеПодразделения;
Эл.ПутьКДанным = "Объект.ТаблицаЧасы." + НазваниеКолонки;
КонецЦикла;
НомерСтроки = 0; // Сброс счетчика здесь допустим
ТаблицаПодразделениеПлан = ЗаполнитьПодразделенияНаСервере();
Для Каждого СтрокаПодразделение Из ТаблицаПодразделениеПлан Цикл
НомерСтроки = НомерСтроки + 1;
НазваниеПодразделения = СтрокаПодразделение.Подразделение.Наименование;
// Добавляем префикс "ТаблицаЧасыПлан_" к имени колонки
НазваниеКолонки = "ТаблицаЧасыПлан_Подразделение" + Строка(НомерСтроки);
ЭлПлан = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаЧасыПлан);
ЭлПлан.Вид = ВидПоляФормы.ПолеВвода;
ЭлПлан.Заголовок = НазваниеПодразделения;
ЭлПлан.ПутьКДанным = "Объект.ТаблицаЧасыПлан." + НазваниеКолонки;
КонецЦикла;
КонецПроцедуры
В этом варианте, даже если счетчик НомерСтроки сбрасывается для каждой таблицы, имена колонок все равно будут уникальными: "ТаблицаЧасы_Подразделение1", "ТаблицаЧасы_Подразделение2" и "ТаблицаЧасыПлан_Подразделение1", "ТаблицаЧасыПлан_Подразделение2". Этот подход является предпочтительным для больших и сложных форм.
Помимо уникальности идентификаторов, существуют и другие важные моменты, которые следует учитывать при динамическом создании элементов формы:
Когда мы добавляем ПолеФормы и привязываем его к пути к данным (например, "Объект.ТаблицаЧасы."+НазваниеКолонки), мы предполагаем, что в источнике данных самой таблицы (Объект.ТаблицаЧасы) уже есть колонка с таким именем. Если Объект.ТаблицаЧасы является табличной частью объекта (например, документа или справочника) или программно созданной ТаблицаЗначений, то нам необходимо убедиться, что соответствующая колонка существует в этом источнике данных. В противном случае, даже при корректном отображении поля, данные не будут корректно сохраняться или отображаться.
Если источником данных является ТаблицаЗначений, то необходимо сначала добавить колонку в ее коллекцию Колонки:
// Предположим, что Объект.ТаблицаЧасы - это ТаблицаЗначений
Если Не Объект.ТаблицаЧасы.Колонки.Найти(НазваниеКолонки) Тогда
Объект.ТаблицаЧасы.Колонки.Добавить(НазваниеКолонки);
КонецЕсли;
// После этого можно добавлять ПолеФормы
Эл = Элементы.Добавить(НазваниеКолонки, Тип("ПолеФормы"), Элементы.ТаблицаЧасы);
// ... остальной код для Эл
Если же таблица на форме привязана к ДинамическийСписок, то подход к добавлению колонок будет другим. В этом случае колонки добавляются не прямым созданием ПолеФормы, а через изменение настроек самого ДинамическогоСписка, обычно путем добавления полей в его запрос или через программное управление доступными полями списка.
Путь к данным (ПутьКДанным) должен точно соответствовать существующему свойству в источнике данных. Если в Объект.ТаблицаЧасы нет поля с именем НазваниеКолонки, то, несмотря на то что поле формы будет отображено, оно не будет корректно связано с данными. Важно убедиться, что имена колонок, используемые в ПутьКДанным, совпадают с именами колонок в фактическом источнике данных.
Хотя платформа 1С иногда и позволяет использовать достаточно гибкие имена для элементов, хорошей практикой является использование простых буквенно-цифровых идентификаторов без пробелов, специальных символов или знаков препинания. Например, "Подразделение"+Строка(НомерСтроки) генерирует правильные идентификаторы. Имена вида "Цех №2" или "Подразделение с пробелом" не подходят для использования в качестве Имя элемента формы или части ПутьКДанным. Поэтому, если название подразделения содержит такие символы, его необходимо предварительно очистить или преобразовать в допустимый формат.
Обработчик ПриСозданииНаСервере является идеальным местом для программного создания элементов формы. На этом этапе форма формируется на сервере, до того как будет отправлена клиенту для отображения. Это обеспечивает корректную инициализацию всех динамических элементов.
Ошибка "Недопустимое значение параметра" при программном добавлении колонок в несколько табличных частей формы в 1С:Предприятии 8.3 чаще всего связана с нарушением требования уникальности идентификаторов элементов формы. Мы рассмотрели два основных способа решения этой проблемы:
Кроме того, не забывайте о необходимости синхронизации создаваемых полей формы с реальной структурой источника данных (например, добавлением колонок в ТаблицаЗначений) и правильном формировании пути к данным. Придерживаясь этих рекомендаций, мы сможете избежать многих типичных ошибок при работе с динамическим интерфейсом в 1С.
Мы вместе проанализировали эту распространенную проблему, рассмотрели ее причины и предложили эффективные решения. Теперь вы вооружены знаниями, которые помогут создавать гибкие и надежные интерфейсы в ваших конфигурациях 1С.