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