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