Как реализовать отбор по расчетным полям в Табличном Поле на обычных формах

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

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

Почему стандартный отбор не работает для расчетных полей

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

Решение проблемы через замену источника данных на Таблицу Значений

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

Шаг 1. Подготовка структуры данных

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


// В модуле формы создадим переменную для хранения данных
Перем ТЗ_Данные;

Процедура ПриОткрытии()
    // Создаем таблицу значений на основании ТЧ документа
    ТЗ_Данные = Товары.Выгрузить();
    
    // Добавляем колонку для расчетного поля, по которому нужен отбор
    ТЗ_Данные.Колонки.Добавить("ОстатокНаСкладе", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
    ТЗ_Данные.Колонки.Добавить("ЦенаСоСкидкой", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
    
    // Заполняем расчетные данные один раз при открытии
    Для Каждого СтрокаТЗ Из ТЗ_Данные Цикл
        СтрокаТЗ.ОстатокНаСкладе = ПолучитьОстатокПоТовару(СтрокаТЗ.Номенклатура);
        СтрокаТЗ.ЦенаСоСкидкой = СтрокаТЗ.Цена * 0.9; // Пример расчета
    КонецЦикла;
    
    // Связываем ТабличноеПоле на форме с нашей ТЗ
    ЭлементыФормы.ТабличноеПолеТовары.Значение = ТЗ_Данные;
    ЭлементыФормы.ТабличноеПолеТовары.СоздатьКолонки();
КонецПроцедуры

Шаг 2. Использование объекта ПостроительОтчета для фильтрации

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


Процедура НастроитьПостроитель()
    Построитель = Новый ПостроительОтчета;
    Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ_Данные);
    
    // Теперь в Построитель.Отбор доступны все колонки нашей ТЗ
    // Можно вывести этот отбор на форму в виде другого ТабличногоПоля
    ЭлементыФормы.ТабличноеПолеОтбор.Значение = Построитель.Отбор;
КонецПроцедуры

Процедура ПрименитьФильтр()
    // Выполняем отбор и получаем результат
    Построитель.Выполнить();
    ТЗ_Результат = Построитель.Результат.Выгрузить();
    
    // Обновляем данные на форме
    ЭлементыФормы.ТабличноеПолеТовары.Значение = ТЗ_Результат;
КонецПроцедуры

Синхронизация данных: Модифицированность и запись

Важный нюанс при работе с копией данных в ТаблицаЗначений — необходимость синхронизации изменений обратно в документ. Если пользователь отредактирует количество или цену в табличном поле, эти данные должны попасть в ЭтотОбъект.Товары. Рассмотрим, как это сделать правильно, чтобы не потерять данные и сохранить свойство Модифицированность формы.

Проанализируем алгоритм синхронизации:

  1. При изменении данных в ТабличноеПоле (событие ПриИзменении или ПослеУдаления), мы должны обновить соответствующую строку в основной табличной части документа.
  2. Перед записью документа необходимо убедиться, что все данные из нашей ТЗ перенесены в ТЧ.
  3. Чтобы расчетные поля пересчитывались при изменении зависимых данных (например, цена при изменении количества), нужно вызвать пересчет конкретной строки в ТЗ.

Процедура ТабличноеПолеТоварыПриИзменении(Элемент)
    // Помечаем форму как измененную
    ЭтаФорма.Модифицированность = Истина;
    
    // Если нужно, пересчитываем расчетные колонки для текущей строки
    ТекущаяСтрока = ЭлементыФормы.ТабличноеПолеТовары.ТекущиеДанные;
    Если ТекущаяСтрока <> Неопределено Тогда
         ТекущаяСтрока.ЦенаСоСкидкой = ТекущаяСтрока.Цена * 0.9;
    КонецЕсли;
КонецПроцедуры

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Синхронизируем ТЗ обратно в ТЧ документа перед сохранением
    Товары.Загрузить(ТЗ_Данные);
КонецПроцедуры

Оптимизация производительности: ПриПолученииДанных

В исходном сообщении упоминалось использование ПриВыводеСтроки. Если данных много, постоянные расчеты в этом событии могут замедлить прокрутку списка. Разберем более современный подход — использование события ПриПолученииДанных. Это событие вызывается один раз для целой "порции" строк, отображаемых на экране. Это позволяет выполнить один пакетный запрос к базе данных (например, для получения остатков по всем товарам в списке сразу), вместо десятков мелких запросов.

Посмотрим на пример логики:

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

Итоги и рекомендации

Подведем итог нашего анализа. Для реализации качественного отбора по расчетным полям в обычных формах 1С 8.2/8.3 лучше всего использовать комбинацию ТаблицаЗначений + ПостроительОтчета. Это дает пользователю гибкость (виды сравнения "В списке", "Между", "Содержит"), а разработчику — полный контроль над данными.

Основные преимущества такого подхода:

Рассмотренный метод является "золотым стандартом" для сложных интерфейсов в конфигурациях типа УПП или КА 1.1, где переход на управляемые формы невозможен или нецелесообразен.

← На главную