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