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

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

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

Анализ типичных ошибок реализации

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


Запрос = Новый Запрос();
Запрос.Текст =
    "ВЫБРАТЬ
    |    Контрагенты.Ссылка
    |ИЗ
    |    Справочник.Контрагенты КАК Контрагенты
    |ГДЕ
    |    Контрагенты.ЗапретОбслуживания = ИСТИНА";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Для каждого ОформлениеСтроки Из ОформленияСтрок Цикл
    Если Выборка.Следующий() = Истина Тогда
        ОформлениеСтроки.ЦветФона = WebЦвета.Красный;
    КонецЕсли;
КонецЦикла;

Выясним причину, почему данный код работает неверно:

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

Другой популярный, но опасный вариант — прямое обращение к реквизиту ссылки внутри цикла:


Для Каждого Оформление Из ОформленияСтрок Цикл
    Если Оформление.ДанныеСтроки.Контрагент.ЗапретОбслуживания Тогда
        Оформление.ЦветФона = WebЦвета.Красный;
    КонецЕсли;
КонецЦикла;

Проанализируем ситуацию: обращение через точку вида Оформление.ДанныеСтроки.Контрагент.ЗапретОбслуживания порождает неявный SQL-запрос к базе данных для каждой строки при каждом скроллинге или обновлении формы. В таблицах на десятки строк это приводит к резкому падению производительности и зависанию клиентского интерфейса (так называемый «запрос в цикле»).

Решение 1. Оптимизация через реквизиты динамического списка (Обычные формы)

Если табличное поле отображает список самого справочника Контрагенты (тип источника — СправочникСписок.Контрагенты), платформе не требуются дополнительные запросы. Достаточно использовать уже закешированные данные строки списка.

Разберем по шагам, как это настроить:

  1. Откроем форму списка справочника в конфигураторе.
  2. В свойствах табличного поля добавим колонку, указав в качестве данных реквизит ЗапретОбслуживания.
  3. Если показывать саму колонку пользователю не требуется, снимем у неё флажок видимости. Присутствие колонки в табличном поле заставляет платформу автоматически считывать этот реквизит в пачку видимых данных.
  4. В обработчике события ПриПолученииДанных применим прямое чтение без обращений через точку:

Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        Если ОформлениеСтроки.ДанныеСтроки.ЗапретОбслуживания Тогда
            ОформлениеСтроки.ЦветФона = WebЦвета.Красный;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Решение 2. Пакетная выборка данных через массив и соответствие (Обычные формы)

Рассмотрим случай, когда табличное поле отображает строки документа или несвязанного списка, где доступна только ссылка на контрагента (ДанныеСтроки.Контрагент), а реквизита ЗапретОбслуживания в самой строке нет.

В этом случае необходимо выполнить один пакетный запрос на всю пачку отображаемых строк с использованием структуры Соответствие для быстрого поиска со сложностью O(1).

Разберем по шагам программную реализацию:

  1. Соберем все непустые ссылки контрагентов из коллекции ОформленияСтрок в массив.
  2. Передадим этот массив параметром в запрос с условием проверки запрета.
  3. Результат запроса поместим в Соответствие, где ключом будет ссылка.
  4. Обойдем видимые строки и раскрасим их при наличии ключа в соответствии.

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


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

Решение 3. Реализация в Управляемых формах (Условное оформление)

Если разработка ведется на управляемых формах, события ПриПолученииДанных и ПриВыводеСтроки на клиенте отсутствуют. Вместо них используется механизм Условного оформления.

Рассмотрим порядок настройки:

  1. В запросе динамического списка убедимся, что поле ЗапретОбслуживания присутствует в выборке.
  2. Откроем свойства формы или свойства самого динамического списка и найдем пункт Условное оформление.
  3. Создадим новый элемент оформления:
    1. Во вкладке Оформление установим свойство Цвет фона или Цвет текста равным красному цвету.
    2. Во вкладке Условие добавим условие: ЗапретОбслуживания Равно Истина.
    3. Во вкладке Оформляемые поля выберем конкретные колонки или оставим поле пустым, чтобы подсвечивалась вся строка целиком.

Также условное оформление динамического списка можно задать программно в процедуре ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    ЭлементОформления = Список.УсловноеОформление.Элементы.Добавить();
    
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.Красный);
    
    ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ЗапретОбслуживания");
    ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    ЭлементУсловия.ПравоеЗначение = Истина;
    ЭлементУсловия.Использование = Истина;
КонецПроцедуры

Совет по эргономике интерфейса: Заливка фона всей строки ярким красным цветом (ОформлениеСтроки.ЦветФона = WebЦвета.Красный) часто делает черный текст нечитаемым и визуально перегружает интерфейс. В реальных конфигурациях рекомендуется выделять только одну колонку (например, ОформлениеСтроки.Ячейки.Контрагент.ЦветФона) либо менять цвет шрифта с помощью свойства ЦветТекста.

← На главную