В практике разработки на платформе 1С:Предприятие часто возникают задачи, связанные с доработкой типовых механизмов печати. В старых конфигурациях (таких как УТ 10.3, УПП 1.3 или КА 1.1) для формирования списка доступных печатных форм используется подсистема УниверсальныеМеханизмы. Проанализируем, как правильно работать с деревом макетов и как эффективно фильтровать объекты метаданных для выбора пользователем.
Разберем ситуацию, когда нам необходимо программно ограничить список печатных форм, которые выводятся пользователю. Рассмотрим исходный код, где дерево макетов получается с помощью функции ПолучитьДеревоМакетовПечати. Основная сложность новичков заключается в попытке вызвать методы у свойства Имя, которое на самом деле является обычной строкой.
Проанализируем структуру строки дерева макетов. В типовых механизмах объект СтрокаДерева содержит следующие колонки:
Текст — отображаемое название печатной формы (например, "Счет на оплату").Имя — внутренний идентификатор макета или процедуры формирования.Расшифровка — служебная информация (часто структура или массив).Для того чтобы наложить отбор по конкретным именам (например, оставить только «ЗаказПокупателя» и «РеализацияТоваровИУслуг»), мы можем использовать два основных подхода.
Это самый простой и наглядный метод. Мы перебираем строки дерева и добавляем в итоговую таблицу только те, которые соответствуют нашим критериям. Рассмотрим пример реализации:
Для Каждого СтрокаДерева Из Дерево.Строки Цикл
// Проверяем, входит ли имя текущей строки в наш список разрешенных
Если СтрокаДерева.Имя = "ЗаказПокупателя" Или СтрокаДерева.Имя = "РеализацияТоваровИУслуг" Тогда
НоваяСтрока = ТаблицаМакетовПечати.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДерева);
Иначе
Продолжить; // Пропускаем ненужные формы
КонецЕсли;
КонецЦикла;
В данном случае мы используем прямое сравнение. Если список имен большой, удобнее использовать коллекцию Массив или СписокЗначений и метод Найти().
Если дерево значений имеет плоскую структуру (без иерархии), мы можем воспользоваться встроенным методом поиска. Рассмотрим, как это сделать с помощью структуры отбора:
Отбор = Новый Структура;
Отбор.Вставить("Имя", "ЗаказПокупателя");
// Метод НайтиСтроки возвращает массив подходящих строк
НайденныеСтроки = Дерево.Строки.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
НоваяСтрока = ТаблицаМакетовПечати.Добавить();
НоваяСтрока.ПечатнаяФорма = Строка.Текст;
НоваяСтрока.Имя = Строка.Имя;
КонецЦикла;
Важное техническое замечание: Метод НайтиСтроки() работает только на том уровне дерева, у которого он вызван. Если ваше дерево содержит вложенные уровни (группировки), данный поиск не увидит подчиненные строки. В таких случаях необходимо использовать рекурсивный обход всех уровней Строки.
Выясним причину, по которой перебор всей коллекции Метаданные.Документы является плохой практикой. В крупных конфигурациях количество видов документов может исчисляться сотнями. Циклический перебор всех метаданных только для того, чтобы предложить пользователю два конкретных типа, — это избыточная нагрузка на систему и неэффективный код.
Рассмотрим, как можно оптимизировать процедуру ТипДокументаНачалоВыбора. Вместо создания таблицы значений вручную и заполнения её в цикле, следует обращаться к нужным объектам метаданных напрямую.
Если нам нужно, чтобы пользователь выбирал только из двух видов документов («Заказ покупателя» и «Реализация товаров»), проанализируем следующий код:
Процедура ТипДокументаНачалоВыбора(Элемент, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Используем СписокЗначений — это более легкий объект для выбора
СписокВыбора = Новый СписокЗначений;
// Добавляем конкретные объекты метаданных без перебора всей коллекции
СписокВыбора.Добавить(Метаданные.Документы.ЗаказПокупателя, "Заказ покупателя");
СписокВыбора.Добавить(Метаданные.Документы.РеализацияТоваровУслуг, "Реализация товаров и услуг");
// Выводим список пользователю для выбора
ВыбранныйЭлемент = ВыбратьИзСписка(СписокВыбора, Элемент);
Если ВыбранныйЭлемент <> Неопределено Тогда
// Записываем результат (объект метаданных) в переменную
ТипДокумента = ВыбранныйЭлемент.Значение;
ОбновитьТаблицуДокументов();
КонецЕсли;
КонецПроцедуры
В этом решении мы полностью исключили цикл Для Каждого по коллекции метаданных. Это не только ускоряет работу интерфейса, но и делает код гораздо более читаемым. Мы напрямую обращаемся к Метаданные.Документы.ИмяДокумента, что гарантирует получение ссылки на описание объекта метаданных.
При работе с программно созданными таблицами значений (как ТаблицаДок в вопросе автора), важно правильно определять типы колонок. Если вы планируете хранить в колонке не описание метаданных, а именно тип документа для сравнения в запросах или операторе ТипЗнч(), используйте объект ОписаниеТипов.
Рассмотрим пример создания типизированной колонки:
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("ДокументСсылка.ЗаказПокупателя"));
МассивТипов.Добавить(Тип("ДокументСсылка.РеализацияТоваровУслуг"));
ОписаниеТипаДокумента = Новый ОписаниеТипов(МассивТипов);
ТаблицаДок = Новый ТаблицаЗначений;
ТаблицаДок.Колонки.Добавить("ТипДокумента", ОписаниеТипаДокумента, "Тип документа");
Резюмируем изученное:
Если внутри обхода строк, либо метод НайтиСтроки, если дерево не имеет вложенности.СтрокаДерева.Имя — это строка, поэтому методы объектов метаданных у неё отсутствуют.Метаданные.Документы целиком, если вам известны конкретные имена документов. Прямое обращение через точку работает мгновенно.СписокЗначений с методом ВыбратьИзСписка подходит лучше, чем временная таблица значений.Эти рекомендации помогут вам создавать более производительные и надежные механизмы в среде 1С:Предприятие 8.