Как быстро окрасить строки в списке обычных форм, чтобы избежать тормозов при прокрутке?

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

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

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

Ключевой принцип работы условного оформления в обычных формах

Чтобы найти эффективное решение, важно понять, как платформа 1С отрисовывает списки и применяет оформление. Проанализируем основные моменты:

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

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

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

Оптимальный алгоритм: кэширование данных для окраски

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

Шаг 1. Подготовка данных для анализа

Самую ресурсоемкую операцию — получение списка элементов, которые нужно окрасить — необходимо выполнить только один раз. Лучшее время для этого — при открытии формы (в обработчике ПриОткрытии) или в момент, когда пользователь активирует нужный режим, например, устанавливает флажок "Выделить номенклатуру".

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

Шаг 2. Кэширование подготовленных данных

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

Рассмотрим два наиболее подходящих для этого типа коллекций:

Важно: эту коллекцию нужно объявить как переменную модуля формы с помощью ключевого слова Перем.


// В самом начале модуля формы
Перем ДанныеДляОкраски; // Тип: Соответствие

Шаг 3. Быстрая проверка и окраска строк

Теперь, когда у нас есть подготовленный и быстрый кэш, код в событии ПриПолученииДанных становится предельно простым и быстрым. Это событие предпочтительнее, чем ПриВыводеСтроки, так как оно обрабатывает сразу пачку строк (массив ОформленияСтрок), что более эффективно.

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

Посмотрим на комплексный пример кода

Проанализируем, как собрать все шаги воедино. Предположим, у нас есть форма списка справочника "Номенклатура" и флажок "ВыделитьНеликвид".


// В самом начале модуля формы
Перем мКэшНеликвида; // Наш кэш, будет хранить Соответствие

// Обработчик нажатия на флажок
Процедура ВыделитьНеликвидПриИзменении(Элемент)
    
    Если ВыделитьНеликвид Тогда
        ЗаполнитьКэшНеликвида();
    Иначе
        мКэшНеликвида = Неопределено; // Очищаем кэш, если флажок снят
    КонецЕсли;
    
    // Обновляем список, чтобы оформление применилось/снялось
    ЭлементыФормы.Список.Обновить();
    
КонецПроцедуры

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

// Обработчик события списка, который выполняется многократно, но очень быстро
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)

    // Если флажок не установлен или кэш пуст, то ничего не делаем
    Если НЕ ВыделитьНеликвид ИЛИ мКэшНеликвида = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Перебираем строки, которые платформа передала для оформления
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        
        ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
        
        // Быстрая проверка наличия ссылки в нашем кэше
        Если мКэшНеликвида.Свойство(ДанныеСтроки.Ссылка) Тогда
             // Если ссылка найдена, устанавливаем цвет фона
             ОформлениеСтроки.Ячейки.Наименование.ЦветФона = WebЦвета.СветлоРозовый;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

В итоге мы получаем:

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

← На главную