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