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

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

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

Проанализируем ситуацию подробнее. Главная причина, по которой мы хотим отследить отбор — это необходимость пересчета итогов в подвале таблицы только по отображаемым (отфильтрованным) строкам. Выясним причину сложностей: в управляемых формах 1С отсутствуют платформенные события, которые реагируют на интерактивные действия пользователя, связанные исключительно с оформлением, такие как стандартный поиск (Ctrl+F), отбор или сортировка Таблицы Значений. Данные в самой таблице при этом не меняются, меняется лишь их отображение.

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

Почему не подходят очевидные варианты?

Прежде чем переходить к рабочим решениям, проанализируем попытки решить задачу "в лоб":

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

Решение 1: Правильный пересчет итогов по видимым строкам

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

Разберем алгоритм: мы в цикле обходим все строки исходной Таблицы Значений и проверяем их идентификаторы. Если метод возвращает Истина, значит строка удовлетворяет текущему отбору на форме и видима пользователю, следовательно, её нужно приплюсовать к нашим итогам.

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


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

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

Решение 2: Разработка собственного механизма отбора

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

Вынесем ключевые поля для фильтрации прямо на форму над нашей таблицей. Например, добавим поле ввода ОтборКонтрагент. К этому полю мы привяжем событие ПриИзменении. В этом событии мы программно сформируем структуру отбора и применим её к таблице.

Разберем по шагам создание своего отбора:


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

Этот паттерн проектирования позволяет полностью контролировать процесс фильтрации и гарантированно выполнять пересчет данных именно тогда, когда пользователь меняет параметры.

Решение 3: Архитектурный переход на Динамический список

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

Как это реализовать?

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

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


&НаСервере
Процедура МойСписокПриОбновленииСоставаПользовательскихНастроекНаСервере(Элемент)
    // Здесь мы можем получить текущие отборы компоновщика настроек
    // и выполнить свой сложный расчет на сервере
    НастройкиКомпоновки = Элемент.КомпоновщикНастроек.ПолучитьНастройки();
    
    // ... логика расчета ...
КонецПроцедуры

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

← На главную