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

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача фильтрации данных в табличной части (ТЧ) на форме. Ситуация усложняется, когда нужно сделать отбор не по прямому реквизиту ТЧ, а по связанным данным — например, по региону контрагента, который указан в документе, ссылка на который хранится в строке. Рассмотрим подробно, почему стандартный механизм ОтборСтрок не видит «виртуальные» колонки и как правильно реализовать этот функционал.

Почему не работает отбор по «пути через точку»

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

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

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

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

  1. Откроем редактор управляемой формы.
  2. Найдем в списке реквизитов наш объект и его табличную часть.
  3. Добавим новый реквизит именно в саму табличную часть (на уровень реквизитов ТЧ формы, а не объекта БД). Назовем его РегионДляОтбора и укажем соответствующий тип (например, СправочникСсылка.Регионы).
  4. Перетащим этот реквизит в элементы формы (в таблицу). Теперь у нас есть колонка, которая реально принадлежит коллекции ТЧ.

Шаг 2. Заполнение данных при создании формы

Поскольку РегионДляОтбора — это реквизит формы, а не базы данных, при открытии документа он будет пуст. Проанализируем, как максимально эффективно заполнить его значениями.

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

Рассмотрим правильный код заполнения в процедуре ПриСозданииНаСервере:


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

КонецПроцедуры

Шаг 3. Установка программного отбора

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


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

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

Исправление ошибок при использовании ОписанияОповещения

Часто в подобных задачах требуется открыть форму контрагента, изменить его регион и обновить данные в основной форме. Разберем типичную ошибку при использовании метода ОткрытьФорму.

Выясним причину, по которой процедура оповещения может не вызываться. Основная проблема часто кроется в неверном подсчете запятых (позиционных параметров) в методе ОткрытьФорму. Описание оповещения является седьмым параметром.

Рассмотрим правильный синтаксис вызова:


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

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

Альтернативный метод: Использование глобальных оповещений

Если механизм ОписаниеОповещенияОЗакрытии кажется слишком громоздким или форма редактирования не закрывается (например, пользователь просто нажал «Записать»), проанализируем использование метода Оповестить().

В форме редактирования контрагента в событии ПослеЗаписи добавим код:


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    Оповестить("ИзмененКонтрагент", Объект.Ссылка, ЭтотОбъект);
КонецПроцедуры

В основной форме, где находится наша табличная часть, используем обработчик ОбработкаОповещения:


&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    Если ИмяСобытия = "ИзмененКонтрагент" Тогда
        // Параметр содержит ссылку на контрагента.
        // Мы можем точечно обновить регион в ТЧ, не закрывая формы.
        ОбновитьРегионДляКонтрагентаНаСервере(Параметр);
    КонецЕсли;
КонецПроцедуры

Подведение итогов

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

← На главную