Как отобрать строки табличной части обработки по списку контрагентов в 1С 8.3?

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

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

В чем суть проблемы с ОтборСтрок?

Автор исходного сообщения столкнулся с ситуацией, когда отбор по одному контрагенту с помощью ЭтаФорма.Элементы.СписокДокументов.ОтборСтрок = Новый ФиксированнаяСтруктура("Контрагент", Справочники.Контрагенты.НайтиПоКоду("")) работает идеально. Но при попытке передать в ФиксированнуюСтруктуру список значений (например, Новый СписокЗначений или массив), отбор перестает работать.

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

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

Эффективные методы отбора табличной части по списку значений

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

1. Программная фильтрация с очисткой и повторным заполнением табличной части (Функция ОтобратьСтрокиПоКритериям)

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

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


Функция ОтобратьСтрокиПоКритериям(Источник, СтруктураКритериев, СтруктураСложныхКритериев = Неопределено) Экспорт
    Перем ВидСравненияСложный;

    Если СтруктураСложныхКритериев = Неопределено Тогда
        СтруктураСложныхКритериев = Новый Структура;
    КонецЕсли;

    ПостроительЗапроса = Новый ПостроительЗапроса;
    ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(Источник);

    Для Каждого Критерий Из СтруктураКритериев Цикл
        НовыйОтбор = ПостроительЗапроса.Отбор.Добавить(Критерий.Ключ);
        СтруктураСложныхКритериев.Свойство(Критерий.Ключ, ВидСравненияСложный);

        Если ВидСравненияСложный = Неопределено Тогда
            НовыйОтбор.Установить(Критерий.Значение);
        Иначе
            НовыйОтбор.Использование = Истина;
            НовыйОтбор.ВидСравнения = ВидСравненияСложный;
            НовыйОтбор.Значение = Критерий.Значение;
        КонецЕсли;
    КонецЦикла;

    Возврат ПостроительЗапроса.Результат;
КонецФункции // ОтобратьСтрокиПоКритериям

Эта функция принимает на вход Источник (обычно это ТаблицаЗначений или другой объект, который может быть обернут в ОписаниеИсточникаДанных), СтруктураКритериев для простых условий и СтруктураСложныхКритериев для указания типа сравнения (например, "ВСписке", "НеРавно" и т.д.).

Проанализируем ее работу по шагам:

  1. Мы создаем новый ПостроительЗапроса. Этот объект обычно используется для конструирования запросов к базе данных, но его также можно эффективно применять для фильтрации таблиц значений в памяти, используя объект ОписаниеИсточникаДанных.
  2. В качестве источника данных для ПостроителяЗапроса мы указываем нашу исходную таблицу значений, которую необходимо отфильтровать: ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(Источник);
  3. Далее мы циклически обходим переданную СтруктуруКритериев. Для каждого критерия добавляется новый элемент отбора в ПостроительЗапроса.Отбор.
  4. Ключевой момент: для поддержки сложных видов сравнения, таких как "ВСписке", функция проверяет наличие соответствующего ключа в СтруктураСложныхКритериев. Если ВидСравненияСложный указан (например, ВидСравнения.ВСписке), то мы явно устанавливаем его для элемента отбора, иначе используется стандартное сравнение "Равно".
  5. После того как все критерии отбора добавлены в ПостроительЗапроса, мы просто получаем результат: Возврат ПостроительЗапроса.Результат;. Метод Результат ПостроителяЗапроса в данном случае вернет новую таблицу значений, содержащую только те строки из исходного Источника, которые соответствуют заданным условиям отбора.

Применение на практике:

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

  1. Создаем список контрагентов для отбора:
    
    СписокКонтрагентовДляОтбора = Новый СписокЗначений();
    СписокКонтрагентовДляОтбора.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000001"));
    СписокКонтрагентовДляОтбора.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000002"));
    // ...добавьте других контрагентов
    
  2. Формируем структуры критериев, указывая "ВСписке" для поля "Контрагент":
    
    СтруктураКритериев = Новый Структура("Контрагент", СписокКонтрагентовДляОтбора);
    СтруктураСложныхКритериев = Новый Структура("Контрагент", ВидСравнения.ВСписке);
    
  3. Вызываем функцию и обновляем табличную часть на форме:
    
    ИсходнаяТаблицаДанных = ЭтаФорма.СписокДокументов; // Предполагаем, что реквизит формы типа ТаблицаЗначений
    ОтфильтрованныеДанные = ОтобратьСтрокиПоКритериям(ИсходнаяТаблицаДанных, СтруктураКритериев, СтруктураСложныхКритериев);
    ЭтаФорма.СписокДокументов.Очистить();
    ЭтаФорма.СписокДокументов.Загрузить(ОтфильтрованныеДанные);
    

Преимущества данного метода:

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

Недостатки:

  1. Производительность: Для очень больших объемов данных (тысячи и десятки тысяч строк) очистка и повторное заполнение табличной части может влиять на производительность и создавать небольшие задержки в пользовательском интерфейсе.
  2. Пользовательский опыт: Фактически происходит пересоздание данных на форме, что может быть нежелательно, если нужно сохранить контекст, например, текущее выделение строк или положение скролла.

2. Добавление вспомогательной булевой колонки

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

Шаги реализации:

  1. Добавление колонки: В табличную часть формы (т.е. в реквизит формы типа ТаблицаЗначений, который связан с элементом формы Таблица) программно или через конфигуратор добавляется новая колонка булевого типа, например, с именем "ОтборПоСписку". Важно отметить, что эта колонка добавляется в коллекцию колонок реквизита формы и не влияет на структуру базы данных.
    
    // Предположим, что "МояТЧ" это реквизит формы типа ТаблицаЗначений,
    // который связан с элементом формы Таблица.
    Если Не МояТЧ.Колонки.Найти("ОтборПоСписку") Тогда
        МояТЧ.Колонки.Добавить("ОтборПоСписку", Новый ОписаниеТипов("Булево"));
    КонецЕсли;
    
  2. Программное заполнение: После этого, при изменении списка контрагентов для отбора, мы программно перебираем все строки табличной части и для тех строк, у которых контрагент входит в наш список, устанавливаем значение вспомогательной колонки "ОтборПоСписку" в Истина. Для остальных строк устанавливаем Ложь.
    
    СписокКонтрагентовДляОтбора = Новый СписокЗначений();
    СписокКонтрагентовДляОтбора.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000001"));
    СписокКонтрагентовДляОтбора.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000002"));
    // ...добавьте других контрагентов
    
    Для Каждого СтрокаТЧ Из МояТЧ Цикл
        Если СписокКонтрагентовДляОтбора.Содержит(СтрокаТЧ.Контрагент) Тогда
            СтрокаТЧ.ОтборПоСписку = Истина;
        Иначе
            СтрокаТЧ.ОтборПоСписку = Ложь;
        КонецЕсли;
    КонецЦикла;
    
  3. Применение отбора: Наконец, мы применяем стандартный ОтборСтрок к элементу формы Таблица, используя нашу вспомогательную булеву колонку:
    
    ЭтаФорма.Элементы.СписокДокументов.ОтборСтрок = Новый ФиксированнаяСтруктура("ОтборПоСписку", Истина);
    

Преимущества данного метода:

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

Недостатки:

  1. Изменение структуры: Требуется добавление вспомогательной колонки в реквизит формы, что немного усложняет структуру данных формы.
  2. Ресурсоемкость: Необходимо вручную перебирать все строки табличной части для установки флага, что может быть ресурсоемко для очень больших объемов данных, хотя обычно это быстрее, чем полная перезагрузка.

3. Использование условного оформления для скрытия строк

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

Принцип работы:

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

Шаги реализации (программно):

  1. Получите или создайте список контрагентов для отбора (СписокКонтрагентовДляОтбора).
  2. Создайте новый элемент условного оформления на форме (обычно это делается программно, если список отбора динамический, или в конфигураторе, если условия более-менее статичны).
    
    // Очищаем существующее условное оформление для чистоты эксперимента
    // или работаем с уже существующим элементом
    ЭтаФорма.УсловноеОформление.Элементы.Очистить(); 
    
    ЭлементУсловногоОформления = ЭтаФорма.УсловноеОформление.Элементы.Добавить();
    ЭлементУсловногоОформления.Использование = Истина;
    
    // 1. Указываем элемент формы, к которому применяется оформление (наша таблица)
    ЭлементУсловногоОформления.ЭлементыФормы.Добавить(ЭтаФорма.Элементы.СписокДокументов);
    
    // 2. Создаем условие: Контрагент НЕ В СПИСКЕ
    // Этот отбор будет скрывать строки, контрагент которых НЕ входит в СписокКонтрагентовДляОтбора
    НовыйЭлементОтбораУсловия = ЭлементУсловногоОформления.Условие.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    НовыйЭлементОтбораУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент");
    НовыйЭлементОтбораУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.НеВСписке;
    НовыйЭлементОтбораУсловия.ПравоеЗначение = СписокКонтрагентовДляОтбора; // Передаем Новый СписокЗначений
    НовыйЭлементОтбораУсловия.Использование = Истина;
    
    // 3. Указываем поля, к которым применяется оформление (все поля строки)
    // Пустое поле означает, что оформление применяется ко всей строке
    ПолеОформления = ЭлементУсловногоОформления.Поля.Элементы.Добавить();
    ПолеОформления.Использование = Истина;
    ПолеОформления.Поле = Новый ПолеКомпоновкиДанных(""); 
    
    // 4. Устанавливаем свойство оформления: Видимость = Ложь
    ЭлементУсловногоОформления.Оформление.УстановитьЗначениеПараметра("Видимость", Ложь);
    

Преимущества данного метода:

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

Недостатки:

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

Заключение

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

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

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

← На главную