Публикация

Быстрый фильтр в дереве TreeDataGrid или новый способ навигации по дереву

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

Мельникова Екатерина на эту тему даже создала идею: community.terrasoft.ua/node/3032.
Главная идея - дерево может находится в двух режимах - дерево и список. При работе с деревом фильтрация невозможно. При работе со списком - мы можем осуществлять поиск нужной нам записи, и при переключении обратно в режим дерева мы позиционируемся на найденной записи.

Основа - режим переключения из дерева в список. В приведенном примере переключение между деревом и списком осуществляется по горячей клавише Ctrl-Q. Включение / отключение фильтра осуществляются по горячей клавише Ctrl-S.

Открываем окно с DataTreeGrid (в данном примере отображены все папки из директория "Program Files", Вы можете загрузить подобную структуру по кнопке "Загрузить папки из директория"):
Дерево для поиска

Допустим, в дереве Вам необходимо найти библиотеку картинок программы Skype. В поле ввода быстрого фильтра набираем текст "Skype" и нажатием Ctrl-S включаем бытрый фильтр, который будет включен при переходе в режим отображения список.
Ввод параметров быстрого фильтра

Переключение просмотра в режим "Список" нажатием Ctrl-Q, после чего можно выбрать необходимую запись:
Переключение в режим

После того, как Вы нашли искомую запись - переключаемся в режим просмотра "Дерево" (Ctrl-Q):
Переключение в режим дерево и позиционирование на найденной записи

Пример сервисов для работы быстрого фильтра в дереве Вы можете найти в присоединенном архиве TreeQuickFilter_Example.rar.

Основные моменты реализации:

Переключение режима "Дерево / Список" осуществляется подстановкой значения свойства "ParentDataFieldName" компонента DataTreeGrid поля "ParentID" если мы хотим видеть дерево или "ID", если нам нуже список (в данном случае возможно переключение без перезапроса данных в базе данных):

function SwitchTreeListViewType() {
        var ParentDataFieldName = grdData.ParentDataFieldName;
        if (ParentDataFieldName == 'ParentID') {
                grdData.ParentDataFieldName = 'ID';
                cbQuickFilter.IsEnabled = true;
        } else {
                grdData.ParentDataFieldName = 'ParentID';
                cbQuickFilter.IsEnabled = false;
        }
        UpdateQuickFilter();
}

Выбор директория для загрузки в таблицу структуры папок:

function LoadFoldersFromDirectory() {
        var FolderNameObject = System.CreateObject('TSObjectLibrary.Value');
        if ((System.SelectDirectory("Выберите папку", '', FolderNameObject))) {
                var FolderName = FolderNameObject.Value;
                var Dataset = dlData.Dataset;
                LoadDirectoryItemsFromFolder(FolderName, Dataset);
        }
}

Загрузка структуры директория осуществляется с помощью рекурсивной функции:

function LoadDirectoryItemsToDataset(Path, Dataset, ParentID) {
        try {
                var Folder = FileSearchGridArea.FSO.GetFolder(Path);
                var Folders = new Enumerator(Folder.SubFolders);
                for (Folders.moveFirst(); !Folders.atEnd(); Folders.moveNext()) {
                        var Item = Folders.item();
                        var Name = Item.Name;
                        var Path = Item.Path;
                        var ID = AddFolderToDataset(Dataset, ParentID, Name, Path);
                        LoadDirectoryItemsToDataset(Path, Dataset, ID);
                }
        } catch(e) {
                ShowErrorDialog(e.message);
        }
}

Обработка горячих клавиш осуществляется в событии OnKeyDown DataTreeGrid:

function DoKeyDown(Control, Key, Shift) {
        var CtrlDown = (Shift & 4) > 0;
        if (CtrlDown) {
                var QKeyCode = 81;
                if (Key.Value == QKeyCode) {
                        SwitchTreeListViewType();
                }
                var SKeyCode = 83;
                if (Key.Value == SKeyCode) {
                        cbQuickFilter.IsChecked = !cbQuickFilter.IsChecked;
                }
        }
}

Данный вариант работы с деревом имеет свои ограничения:

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

Конечно, реализовывать такое в конфигурации трудоемко, но можно. Лучшим решением было бы реализовать быстрый фильтр в ядре в компоненте DataTreeGrid.

Используйте на здоровье.

Поделиться

5 комментариев

Автору - спасибо!
Разработчикам - быстрый фильтр в ядре для компоненты DataTreeGrid!

--
γνῶθι σεαυτόν

А в чем сложности при организации подгрузки узлов дерева по требованию? И с большими объемами бы тогда работалось нормально.

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

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

В данном примере такая задача не решается. Это я и поразумевал фразой "Вы можете предложить большее".

Спасибо. Пригодилось!

Мне тоже пригодилось. Спасибо :smile:

Войдите или зарегистрируйтесь, чтобы комментировать