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