Как раскрасить строку динамического списка при сложных условиях связи данных без стандартного условного оформления

Программист 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача визуального выделения строк в списках (например, в журнале заказов). Стандартное Условное оформление отлично справляется, когда данные для условия находятся в основной таблице списка. Однако, если цвет строки зависит от данных в других регистрах или подчиненных документах (как в случае связи Заказ — Реализация — Регистр сведений), задача усложняется. Использование простых соединений в запросе динамического списка может привести к падению производительности, а иногда и вовсе невозможно без программного вмешательства.

В этой статье мы подробно разберем несколько профессиональных подходов к решению этой задачи, проанализируем их плюсы и минусы, и выясним, как реализовать раскраску эффективно.

Метод 1. Использование обработчика ПриПолученииДанныхНаСервере

Начиная с версии платформы 8.3.10, разработчикам стал доступен мощный инструмент — обработчик события динамического списка ПриПолученииДанныхНаСервере. Рассмотрим подробнее, почему это решение часто является оптимальным. Этот метод позволяет «дообогатить» данные, которые платформа уже выбрала из базы для отображения на экране, и применить к ним оформление.

Проанализируем алгоритм работы этого обработчика:

  1. Платформа выполняет основной запрос списка (например, получает 30 строк для текущего экрана).
  2. Вызывается событие ПриПолученииДанныхНаСервере.
  3. Мы получаем массив ключей (ссылок) именно тех строк, которые будут показаны.
  4. Выполняем один запрос к нужному регистру сведений по этому массиву.
  5. Устанавливаем оформление только для этих строк.

Важно: Никогда не делайте запрос к базе данных внутри цикла по строкам оформления! Это создаст критическую нагрузку на сервер при каждом скролле списка. Правильный пример реализации выглядит так:


&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
    
    // Получаем массив заказов, которые выводятся на экран
    МассивЗаказов = Строки.ПолучитьКлючи();
    
    // Выполняем один запрос ко всей пачке данных
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   РегистрСведенийДанные.Заказ КАК Заказ,
        |   РегистрСведенийДанные.СтатусРаскраски КАК Статус
        |ИЗ
        |   РегистрСведений.ВашРегистр КАК РегистрСведенийДанные
        |ГДЕ
        |   РегистрСведенийДанные.Заказ В(&МассивЗаказов)";
    
    Запрос.УстановитьПараметр("МассивЗаказов", МассивЗаказов);
    РезультатЗапроса = Запрос.Выполнить().Выгрузить();
    
    // Теперь обходим коллекцию оформления строк
    Для Каждого СтрокаОформления Из Строки Цикл
        ДанныеСтроки = РезультатЗапроса.Найти(СтрокаОформления.Ключ, "Заказ");
        
        Если ДанныеСтроки <> Неопределено И ДанныеСтроки.Статус = Истина Тогда
            // Устанавливаем цвет фона
            СтрокаОформления.Оформление["ЦветФона"].Установить(ЦветаСтиля.ОсобыйЦветТекста);
        КонецЕсли;
    КонецЦикла;

КонецПроцедуры

Выясним причину популярности этого метода: он не перегружает основной запрос журнала заказов и работает только с тем объемом данных, который видит пользователь в конкретный момент.

Метод 2. Модификация запроса динамического списка через СКД

Если условие раскраски должно позволять пользователю также фильтровать или сортировать список по этому признаку, то метод с оформлением не подойдет. В этом случае нам придется корректировать сам текст запроса динамического списка. Разберем, как это сделать правильно, чтобы избежать дублей (ведь на один заказ может быть несколько реализаций).

Рассмотрим по шагам добавление поля через ЛЕВОЕ СОЕДИНЕНИЕ:

  1. Откроем настройки динамического списка в форме.
  2. В тексте запроса добавим соединение с вложенным запросом к вашему регистру сведений.
  3. Используем ВЫБРАТЬ РАЗЛИЧНЫЕ или СГРУППИРОВАТЬ ПО, чтобы один заказ не превратился в пять строк в списке из-за пяти связанных документов.

Пример структуры запроса:


ВЫБРАТЬ
    ЖурналДокументов.Ссылка КАК Ссылка,
    ЕСТЬNULL(ПодзапросДанных.НужнаяГалочка, ЛОЖЬ) КАК ФлагДляРаскраски
ИЗ
    ЖурналДокументов.ЗаказыКлиентов КАК ЖурналДокументов
ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ
        ДокументРеализация.ЗаказОснование КАК Заказ,
        МАКСИМУМ(Регистр.Значение) КАК НужнаяГалочка
    ИЗ
        Документ.РеализацияТоваровУслуг КАК ДокументРеализация
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НашРегистр КАК Регистр
        ПО Регистр.Документ = ДокументРеализация.Ссылка
    СГРУППИРОВАТЬ ПО
        ДокументРеализация.ЗаказОснование
) КАК ПодзапросДанных ПО ПодзапросДанных.Заказ = ЖурналДокументов.Ссылка

После добавления такого поля в основной запрос, мы можем использовать стандартное Условное оформление формы, настроив его на колонку ФлагДляРаскраски. Однако помните: сложные соединения могут замедлить открытие журнала, если в нем миллионы записей.

Метод 3. Технология «Виртуального реквизита» в расширении

Проанализируем ситуацию, когда журнал заказов работает слишком медленно, а раскраска нужна мгновенно. В этом случае опытные программисты используют механизм избыточности данных.

Суть метода заключается в следующем:

Выясним преимущества: в динамическом списке нам больше не нужно делать соединений с другими таблицами. Данные лежат в самой таблице заказов. Раскраска через условное оформление будет работать с максимальной производительностью, доступной платформе 1С.

Метод 4. Оптимизация и кэширование

Если вы выбрали первый метод (ПриПолученииДанныхНаСервере), стоит подумать об оптимизации. При быстром скроллинге списка пользователь может многократно пролистывать одни и те же строки. Чтобы не выполнять запрос к регистру каждый раз, мы можем реализовать простейшее кэширование в переменной модуля формы.

Посмотрим на пример логики кэширования:


&НаСервере
Перем КэшДанныхРаскраски; // Переменная модуля формы

&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
    
    Если КэшДанныхРаскраски = Неопределено Тогда
        КэшДанныхРаскраски = Новый Соответствие;
    КонецЕсли;
    
    МассивДляЗапроса = Новый Массив;
    Для Каждого Ключ Из Строки.ПолучитьКлючи() Цикл
        Если КэшДанныхРаскраски.Получить(Ключ) = Неопределено Тогда
            МассивДляЗапроса.Добавить(Ключ);
        КонецЕсли;
    КонецЦикла;
    
    Если МассивДляЗапроса.Количество() > 0 Тогда
        // Выполняем запрос только по тем ключам, которых нет в кэше
        // ... (код запроса) ...
        // Заполняем КэшДанныхРаскраски результатами
    КонецЕсли;
    
    // Применяем оформление из кэша
    Для Каждого СтрокаОформления Из Строки Цикл
        Статус = КэшДанныхРаскраски.Получить(СтрокаОформления.Ключ);
        Если Статус = Истина Тогда
             СтрокаОформления.Оформление["ЦветТекста"].Установить(WebЦвета.Красный);
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Такой подход минимизирует количество обращений к базе данных, делая интерфейс «отзывчивым» даже в тяжелых конфигурациях типа УТ 11 или ERP.

Подведем итог: выбор метода зависит от ваших приоритетов. Если важна скорость разработки и отсутствие лишних реквизитов — используйте ПриПолученииДанныхНаСервере. Если пользователю нужна фильтрация по цвету — модифицируйте запрос СКД. Если же на первом месте стоит производительность огромного журнала — используйте дополнительные реквизиты и подписки на события.

← На главную