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