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

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

Разработка интерфейсов на управляемых формах в 1С часто подбрасывает сложные задачи, связанные с поведением стандартных механизмов платформы. Одной из таких проблем является работа с поиском в иерархических структурах. Представим ситуацию: пользователь нажал Ctrl+F, ввел строку поиска, и дерево на форме отобразило только подходящие элементы. Нам, как разработчикам, необходимо программно перебрать именно эти видимые строки, чтобы выполнить над ними какую-либо операцию (например, массовое изменение реквизита или выгрузку).

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

Почему метод ПроверитьСтроку() работает некорректно для деревьев

Проанализируем сначала поведение самого метода. Метод ПроверитьСтроку() предназначен для проверки того, соответствует ли строка текущим настройкам отбора и поиска элемента формы. Однако при работе с деревьями возникают следующие нюансы:

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

Способ 1: Использование программной установки текущей строки (метод "Обхода")

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

Разберем программный код реализации этого метода. Создадим рекурсивную процедуру для обхода всех уровней дерева:


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

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


&НаКлиенте
Процедура КомандаОбработатьВидимые(Команда)
    
    // Сохраняем позицию пользователя
    СтарыйИдентификатор = Элементы.ДеревоДанных.ТекущаяСтрока;
    
    // Запускаем обход от корня (Реквизит1 - это путь к данным дерева)
    ОпределитьВидимыеСтроки(Реквизит1, Элементы.ДеревоДанных);
    
    // Возвращаем фокус
    Элементы.ДеревоДанных.ТекущаяСтрока = СтарыйИдентификатор;
    
КонецПроцедуры

Способ 2: Особенности режима "Иерархический список"

Проанализируем ситуацию, когда дерево отображается в режиме Иерархический список. В этом режиме поведение метода ПроверитьСтроку() становится более предсказуемым и приближенным к поведению обычной таблицы. Если ваша бизнес-логика позволяет переключить вид отображения, это может решить проблему с корректностью возвращаемых значений Истина / Ложь.

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

Способ 3: Копирование данных в плоскую таблицу (Server-side подход)

Если нам нужно гарантированно и быстро обработать данные, не полагаясь на капризные клиентские методы видимости, рассмотрим вариант с выгрузкой данных. Выясним причину, по которой это может быть эффективнее: поиск Ctrl+F накладывает фильтры, которые сложно "поймать" кодом. Если задача стоит в том, чтобы найти строки по тем же критериям, что и пользователь, лучше сделать это на сервере.

Алгоритм следующий:

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

Важные замечания по производительности

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

Рекомендации по оптимизации:

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

← На главную