Как получить названия реквизитов объекта метаданных и отобразить их в таблице значений на внешней форме 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

Часто в процессе разработки возникает необходимость динамически отображать структуру объектов метаданных. Представим, что у нас есть внешняя форма, и мы хотим, чтобы пользователь мог выбрать любой справочник, документ или другой объект конфигурации, а в таблице на этой же форме автоматически появились названия всех его реквизитов. Разберем, как реализовать такую функциональность в 1С:Предприятие 8.3 на управляемых формах.

Понимание и постановка задачи

Наша основная задача состоит в том, чтобы, выбирая, например, справочник "Номенклатура", в некоторую таблицу на внешней форме поступали названия его реквизитов, а не сами элементы справочника. Это означает, что мы должны работать с метаданными конфигурации, а не с данными информационной базы.

Проще говоря, нам нужно:

  1. Получить объект метаданных по его имени (например, "Справочник.Номенклатура").
  2. Извлечь из этого объекта метаданных список его реквизитов (имя реквизита, тип и т.д.).
  3. Поместить имена этих реквизитов в специальную таблицу значений на форме.
  4. Убедиться, что табличное поле на форме корректно отображает эти данные, возможно, динамически создавая для них колонки.

Подготовка формы и данных

Прежде чем приступить к написанию кода, давайте подготовим нашу внешнюю форму. Нам понадобятся следующие элементы:

  1. Реквизит формы типа ТаблицаЗначений. Назовем его, например, ТаблицаРеквизитов. Именно в этот реквизит мы будем программно добавлять колонки и заполнять их именами реквизитов выбранного объекта метаданных.
  2. Элемент формы ТабличноеПоле. Этот элемент будет визуально отображать содержимое нашего реквизита ТаблицаРеквизитов. Важно связать его свойство ПутьКДанным с реквизитом формы ТаблицаРеквизитов. Например, Элементы.ТабличноеПолеРеквизитов.ПутьКДанным = "ТаблицаРеквизитов".
  3. Реквизит формы для хранения имени объекта метаданных и соответствующий ему элемент формы ПолеВвода. Назовем его ИмяВыбранногоОбъектаМетаданных, тип Строка. В свойстве ТипЗначения этого поля ввода вы можете указать МетаданныеОбъекты или Тип(Метаданные.Справочники), чтобы обеспечить удобный выбор объекта метаданных пользователем. На событие ПриИзменении этого поля ввода мы и будем писать основной код.

Алгоритм получения и отображения реквизитов

Основной код будет выполняться в обработчике события, например, ПриИзменении для поля выбора объекта метаданных. Рассмотрим подробнее каждый шаг.

  1. Шаг 1: Очистка существующих данных

    Прежде чем заполнять таблицу новыми данными, нам всегда нужно очищать старые. Это касается как строк таблицы значений, так и её колонок, а также колонок табличного поля на форме.

    
    // Предположим, что ПеременнаяФормы.ТаблицаРеквизитов - это реквизит формы типа ТаблицаЗначений
    // ИмяВыбранногоОбъектаМетаданных - реквизит формы, хранящий полное имя выбранного объекта метаданных (например, "Справочник.Номенклатура")
    
    // 1. Очищаем старые данные из ТаблицыЗначений
    ПеременнаяФормы.ТаблицаРеквизитов.Очистить();
    ПеременнаяФормы.ТаблицаРеквизитов.Колонки.Очистить();
    

    Также, если мы динамически создаём колонки в табличном поле на форме, их тоже нужно будет очистить перед добавлением новых. Это мы сделаем на последнем шаге.

  2. Шаг 2: Получение объекта метаданных

    Для работы с реквизитами нам нужен сам объект метаданных. Мы можем получить его по полному имени, которое выбрал пользователь.

    
    // ... код из Шага 1 ...
    
    // 2. Получаем объект метаданных
    Если ЗначениеЗаполнено(ИмяВыбранногоОбъектаМетаданных) Тогда
        // Используем Метаданные.НайтиПоПолномуИмени() для универсального поиска по строковому представлению
        ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ИмяВыбранногоОбъектаМетаданных);
    
        Если ОбъектМетаданных <> Неопределено Тогда
            // Продолжаем обработку, если объект найден
        Иначе
            // Обработка случая, когда объект метаданных не найден
            Сообщить("Объект метаданных с именем " + ИмяВыбранногоОбъектаМетаданных + " не найден.");
            Возврат;
        КонецЕсли;
    Иначе
        // Если поле выбора пустое, также очищаем форму и возвращаемся
        Возврат;
    КонецЕсли;
    

    Метод Метаданные.НайтиПоПолномуИмени() является наиболее универсальным, так как позволяет получить объект метаданных любого типа (справочник, документ, регистр и т.д.) по его полному имени, например, "Справочник.Номенклатура" или "Документ.РеализацияТоваровУслуг".

  3. Шаг 3: Добавление колонок в реквизит формы типа ТаблицаЗначений

    Нам понадобится как минимум одна колонка в нашей ТаблицеРеквизитов для хранения имен реквизитов. Давайте назовем её ИмяРеквизита.

    
    // ... код из Шага 2 ...
    
    // 3. Добавляем колонку для имен реквизитов в ТаблицуЗначений
    ПеременнаяФормы.ТаблицаРеквизитов.Колонки.Добавить("ИмяРеквизита", Новый ОписаниеТипов("Строка"));
    
    

    Мы указываем тип "Строка" для этой колонки, так как будем хранить в ней текстовые имена.

  4. Шаг 4: Заполнение ТаблицыЗначений именами реквизитов

    Теперь, когда у нас есть объект метаданных и подготовлена таблица значений, мы можем пройтись по его коллекциям реквизитов и заполнить нашу таблицу. У каждого объекта метаданных есть несколько коллекций, которые нас интересуют:

    • ОбъектМетаданных.Реквизиты: Содержит обычные реквизиты, созданные пользователем или разработчиком.
    • ОбъектМетаданных.СтандартныеРеквизиты: Содержит предопределенные платформой реквизиты (например, Код, Наименование, Ссылка, Дата, Номер и т.д.).
    • ОбъектМетаданных.ТабличныеЧасти: Если вам нужны реквизиты табличных частей, вы также можете пройтись по этой коллекции.

    Пройдемся по коллекциям с помощью цикла Для Каждого ... Из ... Цикл.

    
    // ... код из Шага 3 ...
    
    // 4. Заполняем ТаблицуЗначений реквизитами
    // Сначала обычные реквизиты
    Для Каждого РеквизитМД Из ОбъектМетаданных.Реквизиты Цикл
        НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
        НоваяСтрока.ИмяРеквизита = РеквизитМД.Имя;
    КонецЦикла;
    
    // Затем стандартные реквизиты
    Для Каждого СтандартныйРеквизитМД Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
        НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
        НоваяСтрока.ИмяРеквизита = СтандартныйРеквизитМД.Имя;
    КонецЦикла;
    
    // Если необходимо, можно добавить и табличные части, а также их реквизиты
    // Например, если мы хотим показать, какие табличные части есть у объекта и их колонки:
    // Для Каждого ТабличнаяЧастьМД Из ОбъектМетаданных.ТабличныеЧасти Цикл
    //     НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
    //     НоваяСтрока.ИмяРеквизита = "--- Табличная часть: " + ТабличнаяЧастьМД.Имя + " ---";
    //     
    //     Для Каждого РеквизитТЧМД Из ТабличнаяЧастьМД.Реквизиты Цикл
    //         НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
    //         НоваяСтрока.ИмяРеквизита = "  - " + РеквизитТЧМД.Имя;
    //     КонецЦикла;
    // КонецЦикла;
    

    Каждый элемент в коллекциях Реквизиты и СтандартныеРеквизиты является объектом типа РеквизитМетаданных, у которого есть свойство Имя, что нам и требуется.

  5. Шаг 5: Динамическое создание и настройка колонок табличного поля на форме

    Этот шаг критически важен, если вы хотите, чтобы ваше табличное поле на форме корректно отображало динамически созданные колонки из ТаблицыЗначений. После очистки и добавления колонок в ТаблицуЗначений, мы должны обновить (или создать заново) соответствующие колонки в элементе формы ТабличноеПоле.

    
    // ... код из Шага 4 ...
    
    // 5. Динамическое создание элементов формы (колонок табличного поля)
    // Предполагаем, что Элементы.ТабличноеПолеРеквизитов - это элемент формы, связанный с ТаблицаРеквизитов
    
    Если Элементы.ТабличноеПолеРеквизитов <> Неопределено Тогда
        // Очищаем существующие колонки табличного поля
        // Важно: проходим в обратном порядке, чтобы избежать проблем с индексами при удалении
        Для Индекс = Элементы.ТабличноеПолеРеквизитов.Колонки.Количество() - 1 По 0 Шаг -1 Цикл
            Элементы.ТабличноеПолеРеквизитов.Колонки.Удалить(Элементы.ТабличноеПолеРеквизитов.Колонки[Индекс]);
        КонецЦикла;
    
        // Создаем новую колонку в табличном поле, привязывая ее к колонке ТаблицыЗначений
        Если ПеременнаяФормы.ТаблицаРеквизитов.Колонки.Найти("ИмяРеквизита") <> Неопределено Тогда
            НоваяКолонкаФормы = Элементы.ТабличноеПолеРеквизитов.Колонки.Добавить("ИмяРеквизита", Тип("ПолеФормы"));
            НоваяКолонкаФормы.ПутьКДанным = "ТаблицаРеквизитов.ИмяРеквизита"; // Связываем с колонкой ТаблицыЗначений
            НоваяКолонкаФормы.Заголовок = "Имя Реквизита";
            НоваяКолонкаФормы.Ширина = 20; // Можно задать ширину
            НоваяКолонкаФормы.Вид = ВидПоляФормы.ПолеВвода; // Или ВидПоляФормы.ПолеНадписи, в зависимости от желаемого отображения
        КонецЕсли;
    Иначе
        Сообщить("Элемент формы 'ТабличноеПолеРеквизитов' не найден.");
    КонецЕсли;
    

    Здесь мы сначала удаляем все ранее созданные колонки табличного поля, а затем добавляем новую, указывая ПутьКДанным, который связывает её с колонкой ИмяРеквизита в нашем реквизите формы ТаблицаРеквизитов.

Объединяем весь код в одно событие

Теперь, когда мы рассмотрели все шаги, давайте соберем весь код в один обработчик, например, для события ПриИзменении поля выбора объекта метаданных.


// Обработчик события ПриИзменении поля ввода, где пользователь выбирает объект метаданных
// Например, в модуле формы: Процедура ИмяВыбранногоОбъектаМетаданныхПриИзменении(Элемент)

// Предположим, что:
// - ПеременнаяФормы.ТаблицаРеквизитов - это реквизит формы типа ТаблицаЗначений
// - ПеременнаяФормы.ИмяВыбранногоОбъектаМетаданных - реквизит формы типа Строка,
//   в котором хранится полное имя выбранного объекта метаданных (например, "Справочник.Номенклатура")
// - Элементы.ТабличноеПолеРеквизитов - это элемент формы типа ТабличноеПоле,
//   связанный с ПеременнаяФормы.ТаблицаРеквизитов

// 1. Очищаем старые данные
ПеременнаяФормы.ТаблицаРеквизитов.Очистить();
ПеременнаяФормы.ТаблицаРеквизитов.Колонки.Очистить();

// 2. Получаем объект метаданных
Если ЗначениеЗаполнено(ПеременнаяФормы.ИмяВыбранногоОбъектаМетаданных) Тогда
    ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПеременнаяФормы.ИмяВыбранногоОбъектаМетаданных);

    Если ОбъектМетаданных <> Неопределено Тогда
        // 3. Добавляем колонку для имен реквизитов в ТаблицуЗначений
        ПеременнаяФормы.ТаблицаРеквизитов.Колонки.Добавить("ИмяРеквизита", Новый ОписаниеТипов("Строка"));

        // 4. Заполняем ТаблицуЗначений реквизитами
        // Обычные реквизиты
        Для Каждого РеквизитМД Из ОбъектМетаданных.Реквизиты Цикл
            НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
            НоваяСтрока.ИмяРеквизита = РеквизитМД.Имя;
        КонецЦикла;

        // Стандартные реквизиты
        Для Каждого СтандартныйРеквизитМД Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
            НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
            НоваяСтрока.ИмяРеквизита = СтандартныйРеквизитМД.Имя;
        КонецЦикла;

        // Также можно добавить табличные части, если это требуется
        Если ОбъектМетаданных.ЭтоКоллекцияТабличныхЧастейМетаданных() Тогда // Проверяем, есть ли у объекта табличные части
            Для Каждого ТабличнаяЧастьМД Из ОбъектМетаданных.ТабличныеЧасти Цикл
                НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
                НоваяСтрока.ИмяРеквизита = "--- Табличная часть: " + ТабличнаяЧастьМД.Имя + " ---";
                
                Для Каждого РеквизитТЧМД Из ТабличнаяЧастьМД.Реквизиты Цикл
                    НоваяСтрока = ПеременнаяФормы.ТаблицаРеквизитов.Добавить();
                    НоваяСтрока.ИмяРеквизита = "  - " + РеквизитТЧМД.Имя;
                КонецЦикла;
            КонецЦикла;
        КонецЕсли;

    Иначе
        Сообщить("Объект метаданных с именем " + ПеременнаяФормы.ИмяВыбранногоОбъектаМетаданных + " не найден.");
    КонецЕсли;
КонецЕсли;

// 5. Динамическое создание элементов формы (колонок табличного поля)
Если Элементы.ТабличноеПолеРеквизитов <> Неопределено Тогда
    // Очищаем существующие колонки табличного поля
    Для Индекс = Элементы.ТабличноеПолеРеквизитов.Колонки.Количество() - 1 По 0 Шаг -1 Цикл
        Элементы.ТабличноеПолеРеквизитов.Колонки.Удалить(Элементы.ТабличноеПолеРеквизитов.Колонки[Индекс]);
    КонецЦикла;

    // Создаем новую колонку в табличном поле, привязывая ее к колонке ТаблицыЗначений
    Если ПеременнаяФормы.ТаблицаРеквизитов.Колонки.Найти("ИмяРеквизита") <> Неопределено Тогда
        НоваяКолонкаФормы = Элементы.ТабличноеПолеРеквизитов.Колонки.Добавить("ИмяРеквизита", Тип("ПолеФормы"));
        НоваяКолонкаФормы.ПутьКДанным = "ТаблицаРеквизитов.ИмяРеквизита";
        НоваяКолонкаФормы.Заголовок = "Имя Реквизита";
        НоваяКолонкаФормы.Ширина = 40; // Установим разумную ширину
        НоваяКолонкаФормы.Вид = ВидПоляФормы.ПолеНадписи; // Или ПолеВвода, если требуется редактирование
    КонецЕсли;
Иначе
    Сообщить("Элемент формы 'ТабличноеПолеРеквизитов' не найден. Убедитесь, что он создан и имеет правильное имя.");
КонецЕсли;

// КонецПроцедуры

Важные аспекты и расширения

При работе с метаданными и динамическим изменением формы есть несколько моментов, на которые стоит обратить внимание:

Таким образом, мы видим, что платформа 1С:Предприятие 8.3 предоставляет мощные инструменты для работы с метаданными и динамического управления элементами формы. Используя эти возможности, мы можем создавать гибкие и интерактивные решения, которые адаптируются под структуру конфигурации.

← На главную