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