Member 12561559 Ответов: 3

Как улучшить производительность моего treeview во время заселения


У меня есть иерархия продуктов, которая предварительно заполняет treeview (я не могу использовать population on the fly из - за некоторых других особенностей приложения-поэтому я должен идти по маршруту предварительного заполнения).

Как только я начинаю получать несколько тысяч записей для заполнения, это начинает занимать много времени, даже с beginupdate и endupdate на treeview.

SQL - запросы и формат базы данных не имеют отношения к общей производительности (есть небольшое узкое место, но оно пригодно для жизни) - это население самого Treeview.

Я посмотрел на код FastTreeView в другом месте на CodeProject, который использует словари/массивы для заполнения, а затем заполняет treeview - пример, который приводит этот парень, молниеносен, но я не могу заставить его работать с тем, что я пытаюсь достичь. Я знаю, что ответ, вероятно, будет именно таким - словари или список, но я не могу заставить его функционировать правильно. Итак, вот моя функция (ее рекурсивная часть).

Sub, который вызывает эту функцию, сначала вызывает Setup sub, который заполняет корневые узлы, устанавливает beginupdate, вызывает функцию FindNode ниже, а затем, когда она в конечном итоге возвращается, вызывает endupdate на treeview.

У меня есть около 130 000 элементов, и опять же, Да, мне нужно предварительно заполнить, а не на лету, причина в том, что я использую эту функцию для заполнения типа флажка treeview, который должен быть в состоянии сохранить то, что было выбрано,-и я хочу, чтобы все было красиво и аккуратно, используя тот же базовый код заполнения.

Так что если у кого-то есть какие-то идеи о том, чтобы сократить 50 минут или около того, чтобы заполнить это до нескольких секунд, я буду у вас в долгу :)

<pre> Private Function FindNode(ByVal _nodeCollection As TreeNodeCollection) As TreeNode
        Dim tmpNode As TreeNode
        Dim SQLStr As String
        Dim TotX As Long = 0
        Dim Z As Long = 0

        Try

            For Each _child As TreeNode In _nodeCollection
                TotX = 0

                SQLStr = "SELECT "
                SQLStr = SQLStr & "Product_Category_HierarchyID"
                SQLStr = SQLStr & ","HierarchyName"
                SQLStr = SQLStr & " FROM Product_Category_Hierarchy"
                SQLStr = SQLStr & " WHERE Product_Category_Hierarchy_ParentID=" & _child.Tag
                SQLStr = SQLStr & " ORDER BY HierarchyName"
                Using da As New SQLite.SQLiteDataAdapter(SQLStr, SQLDB)
                    da.SelectCommand.CommandTimeout = 0
                    Using ds As New DataSet
                        da.Fill(ds, "CreateTree")
                        If ds.Tables(0).Rows.Count > 0 Then
                            TotX = ds.Tables(0).Rows.Count - 1
                            For Z = 0 To TotX
                                _child.Nodes.Add(ds.Tables(0).Rows(Z).Item("HierarchyName").ToString).Tag = ds.Tables(0).Rows(Z).Item("Product_Category_HierarchyID").ToString
                            Next
                        End If
                    End Using
                End Using



                tmpNode = FindNode(_child.Nodes)
                If Not tmpNode Is Nothing Then
                    If _CloseTreeNodes = True Then
                        _child.Collapse()
                    End If
                    Return tmpNode
                End If

                If _CloseTreeNodes = True Then
                    _child.Collapse()
                End If
            Next


        Catch ex As Exception
            Messagebox.show(ex.Message)
        End Try

        Return Nothing
    End Function


Что я уже пробовал:

Попробовал поместить beginupdate и endupdate в цикл выше, это не имеет никакого значения.
Я думаю, что мне нужно меньше полудюжины строк кода, чтобы достичь нескольких секунд или нескольких секунд для заполнения, но я потратил около 4 часов, а может быть, и больше, глядя на это без успеха.

3 Ответов

Рейтинг:
2

Wendelius

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

Если вам нужно заполнить все дерево перед использованием, то попробуйте сначала извлечь все данные, а затем использовать эти предварительно извлеченные данные для заполнения дерева. Скорее всего для этого вам понадобится иерархический запрос так что взгляните на Язык запросов SQLite: с предложением[^]

Немного не по теме, но вместо того, чтобы связывать значение с инструкцией SQL, используйте SqliteParameter Класс (Майкрософт.Данных.Базы Данных SQLite) | Майкрософт Документы[^] . Хотя он защищает вас от SQL-инъекций и проблем преобразования типов данных, использование параметров часто также помогает повысить производительность.


MadMyche

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

Рейтинг:
2

RickZeeland

Вы должны поместить beginupdate и endupdate вне цикла, см. пример здесь: Быстрый TreeView[^]

Лучшим вариантом может быть Панель: Реализация Виртуального Treeview[^]


Рейтинг:
0

Member 12561559

Мне удалось заставить класс FastTreeview работать в VB, пришлось внести несколько изменений, но 10 секунд, чтобы загрузить несколько сотен тысяч элементов, работают с удовольствием. Я опубликую статью об этом вместе с возможностями поиска и элементами флажков, мне просто нужно, чтобы он работал в других моих сетках в моем проекте, которые обслуживают эти объекты. Но спасибо за вашу помощь - она породила идеи и помогла мне решить эту проблему самостоятельно, которой я скоро поделюсь ! :)