Как настроить отбор строк в табличной части обычных форм 1С при сравнении двух колонок?

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

При разработке интерфейсов на обычных формах в 1С:Предприятии 8 часто возникает задача динамической фильтрации строк в табличном поле. Типичный пример: у нас есть табличная часть с колонками КоличествоФакт и КоличествоПлан, и нам необходимо оставить видимыми только те строки, в которых фактическое количество отличается от планового (то есть КоличествоФакт <> КоличествоПлан).

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

Почему не работает прямое сравнение двух колонок в «ОтборСтрок»?

Главная причина, по которой разработчики заходят в тупик при решении этой задачи, заключается в ограничениях платформы 1С. Механизм ОтборСтрок спроектирован для сравнения значения конкретной колонки с константой (фиксированным числом, строкой, датой, ссылкой или массивом значений). Он технически не умеет выполнять операцию сравнения вида «Колонка А против Колонки Б» для каждой строки «на лету».

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

Единственно верное решение: использование служебной булевой колонки

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

Шаг 1. Добавление служебной колонки в табличную часть

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

  1. В метаданных (конфигураторе): добавить реквизит табличной части с типом Булево (например, РазличаетсяКоличество). Этот способ прост, но имеет минус — реквизит будет сохраняться в базе данных, что не всегда оправдано для временных интерфейсных задач.
  2. Программно в форме (рекомендуется): добавить колонку только в объект формы (в коллекцию колонок табличной части или непосредственно в дерево/таблицу значений на форме). В таком случае база данных не будет засоряться лишними реквизитами.

Шаг 2. Создание процедуры расчета признака расхождения

Напишем процедуру, которая обходит строки нашей табличной части и программно вычисляет значение для нашей новой колонки РазличаетсяКоличество. Мы будем сравнивать плановое и фактическое количество:


Процедура РассчитатьРазличиеКоличества()
    
    Для Каждого СтрокаТЧ Из Товары Цикл
        // Записываем Истина, если значения колонок не совпадают
        СтрокаТЧ.РазличаетсяКоличество = (СтрокаТЧ.КоличествоФакт <> СтрокаТЧ.КоличествоПлан);
    КонецЦикла;
    
КонецПроцедуры

Шаг 3. Реализация механизма наложения отбора

Теперь мы можем использовать стандартное свойство ОтборСтрок нашего табличного поля. Поскольку в нашей служебной колонке теперь содержатся простые булевы значения (Истина или Ложь), мы легко можем отфильтровать строки по константе Истина. Объединим расчет и установку отбора в одну общую процедуру:


Процедура ОбновитьОтборСтрок()
    
    // Шаг 1: Актуализируем признак различия по всем строкам
    РассчитатьРазличиеКоличества();
    
    // Шаг 2: Настраиваем отбор строк в табличном поле
    ЭлементОтбора = ЭлементыФормы.Товары.ОтборСтрок.РазличаетсяКоличество;
    ЭлементОтбора.ВидСравнения = ВидСравнения.Равно;
    ЭлементОтбора.Значение = Истина;
    ЭлементОтбора.Использование = Истина;
    
КонецПроцедуры

Шаг 4. Настройка обработчиков событий формы

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

  1. В событие формы ПриОткрытии — чтобы отбор накладывался сразу при запуске формы пользователем.
  2. В событие ПриИзменении для колонок КоличествоФакт и КоличествоПлан — чтобы при редактировании ячеек строки автоматически скрывались или появлялись в соответствии с новыми значениями.

Пример привязки к событиям изменения колонок в табличном поле:


Процедура ТоварыКоличествоФактПриИзменении(Элемент)
    ОбновитьОтборСтрок();
КонецПроцедуры

Процедура ТоварыКоличествоПланПриИзменении(Элемент)
    ОбновитьОтборСтрок();
КонецПроцедуры

---

Разбор альтернативных вариантов и работа над ошибками

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

Почему идея скрывать строки в событии «ПриВыводеСтроки» провальна?

Иногда разработчики предлагают отказаться от механизма ОтборСтрок и скрывать строки «на лету» во время отрисовки интерфейса с помощью событий ПриВыводеСтроки или ПриПолученииДанных. Этот подход содержит в себе две критические проблемы:

  1. Визуальный баг интерфейса. В обычных формах 1С у объекта ОформлениеСтроки нет свойства Видимость для всей строки целиком. Если вы попробуете обойти это ограничение и установите Видимость = Ложь для всех отдельных ячеек строки, то ячейки действительно станут невидимыми, но сама строка никуда не исчезнет! Пользователь увидит на экране пустую серую полосу. При наличии сотен скрытых строк форма превратится в сплошное пустое поле, по которому придется долго скроллить.
  2. Колоссальное падение производительности. Событие ПриВыводеСтроки срабатывает непрерывно при любом движении мыши, прокрутке таблицы или изменении размеров окна. Если выполнять в нем сложные логические проверки и попытки перерисовки элементов интерфейса, это неизбежно приведет к сильным «зависаниям» программы даже на небольших объемах данных.

Кто прав в споре про устройство «ОтборСтрок»?

В кругах разработчиков часто возникает путаница относительно типов данных отбора в разных версиях платформы 1С. Важно разграничивать поведение обычных и управляемых форм:

Таким образом, синтаксис вида ЭлементыФормы.Товары.ОтборСтрок.КоличествоФакт.ВидСравнения = ВидСравнения.НеРавно абсолютно корректен и работоспособен в обычных формах. Ошибка автора вопроса заключалась лишь в попытке сравнить две динамические колонки между собой, что в принципе не поддерживается платформой без использования дополнительного булева поля.

---

Важные ограничения и нюансы работы с «ОтборСтрок» в ОФ

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

1. Зависимость от типа источника данных

Свойство ОтборСтрок доступно программисту только тогда, когда источником данных для табличного поля выступает реальный объект типа ТабличнаяЧасть (например, табличная часть документа или справочника). Если вы связали табличное поле на форме с обычной ТаблицейЗначений (ТЗ), попытка обратиться к свойству ОтборСтрок вызовет системную ошибку «Поле объекта не обнаружено». В случае работы с ТЗ вам придется фильтровать сам источник данных (например, используя метод ТЗ Скопировать() с отбором) и заново перезаполнять таблицу на форме.

2. Отсутствие индексации и производительность

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

3. Особенности обхода строк в коде после наложения отбора

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


// Внимание! Этот цикл все равно обойдет ВСЕ строки, включая скрытые отбором!
Для Каждого СтрокаТЧ Из Товары Цикл
    // Ваша обработка данных
КонецЦикла;

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


Для Каждого СтрокаТЧ Из Товары Цикл
    // Проверяем значение нашей служебной колонки
    Если Не СтрокаТЧ.РазличаетсяКоличество Тогда
        Продолжить; // Пропускаем строки, не прошедшие отбор
    КонецЕсли;
    
    // Обрабатываем только видимые пользователю строки
КонецЦикла;

Использование этого несложного правила гарантирует, что бизнес-логика вашего документа или обработки будет работать в строгом соответствии с тем, что видит конечный пользователь на своем экране.

← На главную