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

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

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

Анализируем проблему: почему нельзя просто «прочитать» сортировку?

Прежде всего, нам необходимо понять важное ограничение платформы «1С:Предприятие 8». Для таблиц формы, отображающих ДанныеФормыДерево или ДанныеФормыКоллекция, не существует прямого метода, позволяющего программно получить текущее состояние сортировки, которую пользователь установил через стандартное меню «Еще — Сортировать по...». В отличие от динамических списков, где мы можем обратиться к КомпоновщикуНастроек, дерево на форме скрывает эти параметры внутри визуального состояния элемента. Следовательно, если мы просто обновим данные, платформа не применит предыдущую визуальную сортировку к новым строкам автоматически.

Способ 1: Использование собственных команд сортировки

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

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

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

Способ 2: Программная сортировка через объект ДеревоЗначений

Когда нам нужно внести изменения в дерево и сохранить при этом порядок, мы используем преобразование данных формы в объект и обратно. Разберем по шагам, как это реализовать на сервере:

Допустим, у нас есть реквизит формы Дерево1. Чтобы применить сортировку ко всем уровням иерархии рекурсивно, используем следующий код:


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

Обратите внимание на метод Сортировать(). Крайне важно использовать второй параметр Истина, если ваше дерево имеет несколько уровней вложенности. Это гарантирует, что порядок будет соблюден на всех уровнях иерархии.

Способ 3: Сохранение фокуса на текущей строке

При использовании метода ЗначениеВРеквизитФормы() или полной перезагрузке дерева пользователь может столкнуться с тем, что активная строка «прыгает» в самое начало списка. Чтобы обеспечить комфортную работу, нам нужно программно восстановить положение курсора. Выясним, как это сделать правильно.

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


&НаКлиенте
Процедура ОбновитьИСохранитьФокус()
    // Сохраняем идентификатор текущей строки перед обновлением
    ТекущийИдентификатор = Элементы.ТаблицаДерево.ТекущаяСтрока;
    
    ОбновитьДанныеДереваНаСервере();
    
    // Пытаемся вернуть фокус на ту же строку
    Если ТекущийИдентификатор <> Неопределено Тогда
        Элементы.ТаблицаДерево.ТекущаяСтрока = ТекущийИдентификатор;
    КонецЕсли;
КонецПроцедуры

Важный нюанс: если вы полностью очищаете дерево методом Очистить() и заполняете его заново, старые идентификаторы строк перестанут существовать. В этом случае вам придется искать новую строку по ключевым полям (например, по уникальному коду или ссылке) и получать её идентификатор с помощью метода НайтиПоИдентификатору() или путем обхода коллекции Дерево1.ПолучитьЭлементы().

Альтернативный подход: Динамические списки и СКД

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

Динамический список позволяет:

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

Заключение и рекомендации

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

← На главную