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