Как реализовать сложное условное оформление в динамическом списке 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на управляемых формах 1С программисты часто сталкиваются с задачей визуального выделения данных. Если условие оформления простое (например, Сумма > 100 или Статус = Передан), мы используем стандартное условное оформление. Однако, когда требуется проанализировать связанные данные или выполнить расчеты (например, «покрасить строку, если у данного контрагента менее 3 документов в текущем периоде»), стандартных средств настройки компоновки может быть недостаточно. Рассмотрим способы решения этой задачи, начиная от классических запросов и заканчивая современными методами обработки данных на сервере.

Метод 1. Использование произвольного запроса в динамическом списке

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

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

Пример текста запроса для динамического списка документов:


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

После добавления такого поля в список, мы переходим на вкладку Условное оформление (в конфигураторе или программно в форме) и устанавливаем условие: КоличествоДокументов < 3. Плюс этого метода в том, что по полю КоличествоДокументов пользователь сможет выполнять стандартные группировки, сортировки и отборы.

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

В современных версиях платформы 1С (начиная с 8.3.10) появился механизм, заменяющий старое событие ПриВыводеСтроки. Рассмотрим подробнее событие ПриПолученииДанныхНаСервере. Оно позволяет программно модифицировать оформление строк непосредственно перед их передачей с сервера на клиент.

Выясним причину, почему этот метод считается более гибким: он позволяет выполнять вычисления, которые крайне сложно или невозможно описать на языке запросов СКД (например, обращение к внешним системам, сложная математика в коде или проверка прав доступа). Однако здесь важно помнить об оптимизации, чтобы не спровоцировать проблему «N+1 запрос».

Разберем алгоритм правильной реализации этого события:

  1. Сначала мы собираем все идентификаторы объектов (ссылки), которые попали в текущую порцию данных для отображения.
  2. Выполняем один пакетный запрос ко всем собранным объектам.
  3. Обходим коллекцию строк оформления и применяем визуальные изменения.

Посмотрим на пример кода в модуле управляемой формы:


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

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

Важный нюанс: параметр Строки представляет собой карту (соответствие), где ключ — это идентификатор строки, а значение — объект ОформлениеСтрокиДинамическогоСписка. Мы обращаемся к свойству Данные, чтобы получить значения полей текущей записи.

Сравнение подходов и важные ограничения

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

Преимущества метода с запросом в динамическом списке:

Ограничения метода ПриПолученииДанныхНаСервере:

Программное управление Условным оформлением

Иногда порог в 3 документа может меняться. В этом случае мы можем программно изменять настройки условного оформления динамического списка. Это полезно, когда нужно применить оформление по полю, которое уже есть в запросе, но условия оформления динамичны.

Рассмотрим пример создания элемента оформления программно:


&НаСервере
Процедура УстановитьОформлениеПрограммно()
    
    ЭлементОформления = Список.УсловноеОформление.Элементы.Добавить();
    
    // Устанавливаем, что именно мы меняем (например, цвет текста)
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветТекста", ЦветаСтиля.ОсобыйТекст);
    
    // Указываем условие: КоличествоДокументов меньше порога
    ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("КоличествоДокументов");
    ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Меньше;
    ЭлементОтбора.ПравоеЗначение = 3;
    
    // Определяем, какие поля красить (если не указать - покрасится вся строка)
    ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
    ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("Контрагент");
    
КонецПроцедуры

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

← На главную