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