Цитата(Softaz @ 17.2.2008, 23:23 ) | Очень хочу посмотреть на такое дерево, когда в БД будет тыщь 10 узлов smile |
10 тысяч это совсем немного, надо поставить TreeView.BeginUpdate до начала заливки и TreeView.EndUpdate после, всё работает мгновенно. Вообще, я могу конечно тебе дать такую программу, но ничего интересного в ней нет, загрузка 10 тысяч проходит мгновенно даже на пентиуме II.
Поскольку свой код мне писать влом буду комментировать то, что сделал thomas. Про BeginUpdate и EndUpdate было сказано, в стандартных примерах МСДН ещё курсор меняют на ожидающий, да и самому можно, что угодно придумать.
Интересно так же отметить, что TreeNode.Name (в коде node.Name) в .NET Framework 1.1 отсутствует. Значит был использован .NET Framework 2.0, а может и выше, за последним я уже не следил. Это строковый идентификатор, а ключ таблицы как правило int (целочисленный).
В общем, техника работы с древовидным списком сводится к следующему. Вот в вышеупомянутом примере есть treeView1.Nodes.Add(node);. node создан так TreeNode node = new TreeNode();, т.е. от класса TreeNode. А нужно создать новый класс, наследованный от TreeNode, добавить туда необходимые свойства, например идентификатор таблицы, тип узла и так далее, и создавать экземпляр этого класса.
Потом преобразуя его в TreeNode с помощью метода Add класса TreeNodeCollection добавляем его в древовидный список. Назову пронаследованный класс для удобства InheritTreeNode. Ну так вот, раз объект находящийся в коллекции древоузлов изначально был создан конструктором InheritTreeNode, то при извлечении TreeNode можно сделать обратное преобразование в InheritTreeNode.
То есть преобразования InheritTreeNode => TreeNode получаются в любом случае, а для TreeNode => InheritTreeNode надо чтобы объект был создан конструктором класса более глубоким по иерархии, там нюансы, но это уже заморочки языка. Таким образом программист получает расширенный функционал (узлы могут изображать папки, файлы, или всё что в голову придёт, дополнительный код позволяет правильно обрабатывать узлы) и синхронизацию с базой данных (свойство ID из бд или отсоединённого объекта). И не стоит забывать о том, что переопределять можно не только узлы, но и вообще всё что угодно.
По поводу заливки. Некоторые применяют заливку вначале работы программы и загрузку из древосписка в конце. Недостаток в том, что при аварийном завершение программы (электричество отрубили, или сглючила программа, ОС и так далее), данные не запишутся. Приведённый мной способ позволяет держать синхронизацию в любой момент времени, но опять же, от способа зависит и возможная структура таблицы для хранения древовидных узлов.
Вообще, способов хранения данных не мало. Например, в загрузке и выгрузке при открытии и закрытии программы, общую структуру можно представить как полностью раскрытый список, там так прямо и записывают, а таблицу просто очищают перед записью. У thomas например две таблицы, одна группа, а другая то что внутри, и из группы происходит постоянный скачок внутрь другой таблицы, проход по ней фильтром в поисках нужных узлов, и по строковой переменной.
Как известно древовидный список основывается на древовидном графе, он в свою очередь является подмножеством общего графа. А значит для записи любого уровня вложенности узлов достаточно таблицу связей и таблицу узлов. Однако в данной и конкретной задаче этого не требуется.Что же ещё можно сказать, ну пожалуй, когда я делал похоже, то во вложенном цикле использовал DataRow.GetChildRows. У меня была установлена зависимость, причём я её просто сгенерил через xsd.
Ладно, всё таки напишу кое-какой код, только тут сразу стоит учитывать, что без свойств и нормальных конструкторов и переопределений, его ценность с точки зрения рефакторинга сомнительна. В общем, этот код, только для общего понимания, даже тестировать его не буду на работоспособность.
узел с полями (а надо бы свойства)
Код | Public Class InheritTreeNode Inherits TreeNode
Public isMainPart As New Boolean Public idMainPart As New Integer Public idSubPart As New Integer End Class
|
класс, по идее нужно писать переопределение от TreeView, но у меня обычный объект, так как в первом случае надо понимать, что такое базовый конструктор, а такие люди уже не задают вопросы
Код | '... какой-то класс
Public trvMyTree As TreeView ' Набор данных. Friend WithEvents dsMyDataset As MyDataset
Public Sub FillMyTreeView() BeginUpdate()
trvMyTree.Nodes.Clear()
Dim nsMainPart As InheritTreeNode Dim ndSubNode As InheritTreeNode
For Each rowMainPart As DataRow In dsMyDataset.tblMainPart.Rows
nsMainPart = New InheritTreeNode nsMainPart.isMainPart = True nsMainPart.idMainPart = CInt(rowMainPart(0)) nsMainPart.Text = CStr(rowMainPart(1)) trvMyTree.Nodes.Add(nsMainPart)
For Each rowSubPart As DataRow In row.GetChildRows(dsMyDataset.Relations("tblMainParttblSubPart")) ndSubNode = New InheritTreeNode ndSubNode.isMainPart = False ndSubNode.idMainPart = CInt(rowMainPart(0)) ndSubNode.idSubPart = CInt(rowSubPart(0)) ndSubNode.Text = CStr(rowSubPart(1)) node.Nodes.Add(ndSubNode) Next
Next
EndUpdate() End Sub 'FillMyTreeView
|
вызов где-то на задворках вселенной, учитываем что во время работы предыдущего куска, в нём должна быть установлена ссыкла на этот древосписок
Код | Private Sub TreeView1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TreeView1.DoubleClick If Not TreeView1.SelectedNode Is Nothing Then
Dim sln As InheritTreeNode = CType(TreeView1.SelectedNode, InheritTreeNode)
If sln.isMainPart Then MsgBox("Главная часть: " & sln.idMainPart) Else MsgBox("Подразделение: " & sln.idSubPart & vbNewLine & "находится в " & sln.idMainPart & " главной части") End If
End If
End Sub
|
Вот как-то так и надо писать, только с учётом принципов ООП, а не как попало. |