亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁(yè) > 編程 > Visual Basic > 正文

TreeView控件的設(shè)計(jì)實(shí)例

2023-06-12 12:11:28
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

本文重點(diǎn)講解了TreeView控件的使用方法。TreeView控件具有豐富的功能,可以運(yùn)用到很多場(chǎng)合。摘要:講述了如何向 TreeView 控件添加數(shù)據(jù)綁定功能,它是一系列 Microsoft Windows 控件開(kāi)發(fā)示例之一。您可以將本文與相關(guān)的概述文章結(jié)合起來(lái)閱讀。

簡(jiǎn)介

在可能的情況下,您應(yīng)該先使用些現(xiàn)成的控件;因?yàn)樘峁┑?Microsoft® Windows® 窗體控件中包含大量編碼和測(cè)試成果,如果您要放棄它們從頭開(kāi)始,無(wú)疑是一種巨大的浪費(fèi)?;诖?,在本例中,我將繼承一個(gè)現(xiàn)有 Windows 窗體控件 TreeView ,然后對(duì)其進(jìn)行自定義。在下載該 TreeView 控件的代碼時(shí),您還會(huì)得到附加的控件開(kāi)發(fā)示例,以及一個(gè)演示如何與其他數(shù)據(jù)綁定控件一起使用該增強(qiáng) TreeView 的示例應(yīng)用程序。

設(shè)計(jì)數(shù)據(jù)綁定樹(shù)視圖

對(duì)于 Windows 開(kāi)發(fā)人員來(lái)說(shuō),向 TreeView 控件添加數(shù)據(jù)綁定是經(jīng)常會(huì)遇到的問(wèn)題,但由于 TreeView 和其他控件(如 ListBoxDataGrid)存在一個(gè)主要差別(即 TreeView 顯示分層數(shù)據(jù)),因而基本控件目前還不支持此功能(也就是說(shuō),我們還必須使用它)。給定一個(gè)數(shù)據(jù)表,您就會(huì)很清楚如何在 ListBoxDataGrid 中顯示該信息,但利用 TreeView 的分層特點(diǎn)來(lái)顯示同樣的數(shù)據(jù)就不那么簡(jiǎn)單明了。就個(gè)人而言,我在使用 TreeView 顯示數(shù)據(jù)時(shí)曾應(yīng)用過(guò)許多不同的方法,但有一種方法最常用:按某些字段將表中的數(shù)據(jù)分組,如圖 1 所示。

圖 1:在 TreeView 中顯示數(shù)據(jù)

  在本例中,我將創(chuàng)建一個(gè) TreeView 控件,在該控件中可傳遞一個(gè)平面數(shù)據(jù)集(如圖 2 所示),并可輕松地生成圖 1 所示的結(jié)果。

圖 2:平面結(jié)果集,包含創(chuàng)建圖 1 所示的樹(shù)所需的所有信息

  在開(kāi)始編碼之前,我為新控件想出了一個(gè)可以處理該特定數(shù)據(jù)集的設(shè)計(jì),并希望它能夠適用于許多其他類似的情形。添加一個(gè)足可以使用大多數(shù)平面數(shù)據(jù)創(chuàng)建分層結(jié)構(gòu)的組集合,在該集合中為每一級(jí)分層均指定一個(gè)分組字段、顯示字段和值字段(任一或所有字段均應(yīng)相同)。為了將圖 2 所示的數(shù)據(jù)轉(zhuǎn)變成圖 1 所示的 TreeView,我的新控件要求您定義兩個(gè)分組級(jí)別 Publisher 和 Title,并將 pub_id 定義為 Publisher 組的分組字段,將 title_id 定義為 Title 組的分組字段。除分組字段以外,還需要為每個(gè)組指定顯示和值字段,以確定在相應(yīng)組節(jié)點(diǎn)上顯示的文本以及用來(lái)唯一標(biāo)識(shí)特定組的值。當(dāng)遇到此類數(shù)據(jù)時(shí),請(qǐng)使用 pub_name/pub_idtitle/title_id 作為這兩個(gè)組的顯示/值字段。作者信息將變成樹(shù)的葉節(jié)點(diǎn)(分組分層結(jié)構(gòu)末端的節(jié)點(diǎn)),您還需要為這些節(jié)點(diǎn)指定 ID (au_id) 和顯示 (au_lname) 字段。

  構(gòu)建自定義控件時(shí),在開(kāi)始編碼之前確定程序員對(duì)該控件的使用方法將有助于提高控件的使用效率。這種情況下,我希望程序員(在給定了前面所示的數(shù)據(jù)和所需結(jié)果的情況下)能夠使用如下幾行代碼完成分組:

 

With DbTreeControl
.ValueMember = "au_id"
.DisplayMember = "au_lname"

.DataSource = myDataTable.DefaultView
.AddGroup("Publisher", "pub_id", "pub_name", "pub_id")
.AddGroup("Title", "title_id", "title", "title_id")
End With


  注意:這并不是我最終編寫的代碼行,但兩者相差不多。在開(kāi)發(fā)控件的過(guò)程中,我意識(shí)到需要將與 TreeView 關(guān)聯(lián)的 ImageList 中的圖像索引與每個(gè)分組級(jí)別相關(guān)聯(lián),因此必須向 AddGroup 方法中額外添加一個(gè)參數(shù)。

  為了真正構(gòu)建該樹(shù),我將瀏覽數(shù)據(jù)并查找字段(指定為每個(gè)分組的分組值)的更改,同時(shí)在必要時(shí)創(chuàng)建新分組節(jié)點(diǎn),并針對(duì)每個(gè)數(shù)據(jù)項(xiàng)創(chuàng)建一個(gè)葉節(jié)點(diǎn)。由于存在分組節(jié)點(diǎn),因此總節(jié)點(diǎn)數(shù)將大于數(shù)據(jù)源中的項(xiàng)目數(shù),但基礎(chǔ)數(shù)據(jù)中的每個(gè)項(xiàng)有且僅有一個(gè)葉節(jié)點(diǎn)。

圖 3:分組節(jié)點(diǎn)與葉節(jié)點(diǎn)

  葉節(jié)點(diǎn)和分組節(jié)點(diǎn)之間的區(qū)別(如圖 3 所示)對(duì)本文的余下部分具有重要意義。我決定將這兩類節(jié)點(diǎn)區(qū)別對(duì)待,為每一類節(jié)點(diǎn)分別創(chuàng)建自定義節(jié)點(diǎn),并根據(jù)所選的節(jié)點(diǎn)類型引發(fā)不同的事件。

  實(shí)現(xiàn)數(shù)據(jù)綁定

  為該控件編寫代碼的第一步是創(chuàng)建項(xiàng)目和相應(yīng)的起始類。在本例中,我首先創(chuàng)建一個(gè)新 Windows 控件庫(kù),然后刪除默認(rèn)的 UserControl 類,并用一個(gè)從 TreeView 控件繼承的新類來(lái)代替它:
 

  Public Class dbTreeControl
   Inherits System.Windows.Forms.TreeView
 

  從這時(shí)起,我將設(shè)計(jì)一個(gè)可以放入到窗體中的控件,并使其具有常規(guī)的 TreeView 的外觀和功能。下一步是開(kāi)始添加旨在處理在 TreeView 中加入的新功能所需的代碼,即數(shù)據(jù)綁定和分組數(shù)據(jù)。

  添加 DataSource 屬性

  我的新控件的所有功能都很重要,但構(gòu)建復(fù)雜數(shù)據(jù)綁定控件的兩個(gè)關(guān)鍵問(wèn)題是處理 DataSource 屬性和從數(shù)據(jù)源的每個(gè)對(duì)象中檢索單個(gè)項(xiàng)目。

  創(chuàng)建屬性例程

  首先,任何用于實(shí)現(xiàn)復(fù)雜數(shù)據(jù)綁定的控件都需要實(shí)現(xiàn)一個(gè) DataSource 屬性例程,并保持適當(dāng)?shù)某蓡T變量:

 

Private m_DataSource As Object

_
Public Property DataSource() As Object
Get
Return m_DataSource
End Get
Set(ByVal Value As Object)
If Value Is Nothing Then
cm = Nothing
GroupingChanged()
Else
If Not (TypeOf Value Is IList Or _
TypeOf Value Is IListSource) Then
' 不是針對(duì)該用途的有效數(shù)據(jù)源
Throw New System.Exception("無(wú)效 DataSource")
Else
If TypeOf Value Is IListSource Then
Dim myListSource As IListSource
myListSource = CType(Value, IListSource)
If myListSource.ContainsListCollection = True Then
Throw New System.Exception("無(wú)效 DataSource")
Else
' 對(duì),對(duì)。它是有效的數(shù)據(jù)源
m_DataSource = Value
cm = CType(Me.BindingContext(Value), _
CurrencyManager)
GroupingChanged()
End If
Else
m_DataSource = Value
cm = CType(Me.BindingContext(Value), _
CurrencyManager)
GroupingChanged()
End If
End If
End If
End Set
End Property
 

  IList 接口

  可用作復(fù)雜數(shù)據(jù)綁定數(shù)據(jù)源的對(duì)象通常都支持,該接口將數(shù)據(jù)公開(kāi)為對(duì)象集合,并提供若干有用屬性,如 Count。我的新 TreeView 控件要求在其綁定中使用一個(gè)支持 IList 的對(duì)象,但使用另一個(gè)接口也可以,因?yàn)樗峁┝艘粋€(gè)獲取 IList 對(duì)象的簡(jiǎn)便方法 (GetList)。當(dāng)設(shè)置 DataSource 屬性后,我首先確定是否提供了有效的對(duì)象,即一個(gè)支持 IListIListSource 的對(duì)象。我真正想要的是 IList,因此如果對(duì)象僅支持 IListSource(例如 DataTable),那么我將使用該接口的 GetList() 方法獲得正確的對(duì)象。

  某些實(shí)現(xiàn) IListSource 的對(duì)象(如 DataSet)實(shí)際上包含多個(gè)由 ContainsListCollection 屬性表示的列表。如果該屬性為 True,則 GetList 將返回一個(gè)表示列表(包含多個(gè)列表)的 IList 對(duì)象。在我的示例中,我決定支持直接連接到 IList 對(duì)象或僅包含一個(gè) IList 對(duì)象的 IListSource 對(duì)象,并忽略需要附加工作來(lái)指定數(shù)據(jù)源的對(duì)象,如 DataSet

注意:如果要支持此類對(duì)象(DataSet 或與之類似的對(duì)象),您可以再添加一個(gè)屬性(如 DataMember)來(lái)指定用于綁定的特定子列表。

  如果提供的數(shù)據(jù)源有效,則最終結(jié)果是創(chuàng)建的實(shí)例 (cm = Me.BindingContext(Value))。由于該實(shí)例將用于訪問(wèn)基礎(chǔ)數(shù)據(jù)源、對(duì)象屬性和位置信息,因此被存儲(chǔ)在局部變量中。

  添加顯示和值成員屬性

  擁有 DataSource 是實(shí)現(xiàn)復(fù)雜數(shù)據(jù)綁定的第一步,但該控件需要了解數(shù)據(jù)的哪些特定字段或?qū)傩詫⒂米黠@示和值成員。Display 成員將用作樹(shù)節(jié)點(diǎn)的標(biāo)題,而 Value 成員可通過(guò)節(jié)點(diǎn)的 Value 屬性進(jìn)行訪問(wèn)。這些屬性都是字符串,表示字段或?qū)傩悦?,可以方便地添加到控件中?/p>

 

Private m_ValueMember As String
Private m_DisplayMember As String

_
Public Property ValueMember() As String
Get
Return m_ValueMember
End Get
Set(ByVal Value As String)
m_ValueMember = Value
End Set
End Property

_
Public Property DisplayMember() As String
Get
Return m_DisplayMember
End Get
Set(ByVal Value As String)
m_DisplayMember = Value
End Set
End Property

  在此 TreeView 中,這些屬性將僅表示葉節(jié)點(diǎn)的 DisplayValue 成員,每個(gè)分組級(jí)別的相應(yīng)信息將在 AddGroup 方法中指定。

  使用 CurrencyManager 對(duì)象

  在前面探討的 DataSource 屬性中,創(chuàng)建了一個(gè) CurrencyManager 類的實(shí)例,并存儲(chǔ)在類級(jí)別變量中。通過(guò)該對(duì)象訪問(wèn)的 CurrencyManager 類是實(shí)現(xiàn)數(shù)據(jù)綁定的關(guān)鍵部分,因?yàn)樗哂械膶傩浴⒎椒ê褪录蓪?shí)現(xiàn)以下功能:

  • 訪問(wèn)數(shù)據(jù)源的基礎(chǔ) IList 對(duì)象
  • 在數(shù)據(jù)源中檢索和設(shè)置對(duì)象字段或?qū)傩?,以?/li>
  • 使您的控件與同一窗體中的其他數(shù)據(jù)綁定控件同步。

  檢索屬性/字段值

  CurrencyManager 對(duì)象允許您通過(guò)它的 GetItemProperties 方法從數(shù)據(jù)源的單個(gè)項(xiàng)中檢索屬性或字段值,如 DisplayMemberValueMember 字段的值。然后使用 PropertyDescriptor 對(duì)象獲取特定列表項(xiàng)上的特定字段或?qū)傩缘闹?。下面的代碼片斷顯示了這些 PropertyDescriptor 對(duì)象的創(chuàng)建方法以及如何使用 GetValue 函數(shù)獲取基礎(chǔ)數(shù)據(jù)源中某一項(xiàng)的屬性值。請(qǐng)注意 CurrencyManager 對(duì)象的 List 屬性:通過(guò)它可以訪問(wèn)該控件綁定到的 IList 實(shí)例:

 

Dim myNewLeafNode As TreeLeafNode
Dim currObject As Object
currObject = cm.List(currentListIndex)
If Me.DisplayMember <> "" AndAlso Me.ValueMember <> "" Then
' 添加葉節(jié)點(diǎn)?
Dim pdValue As System.ComponentModel.PropertyDescriptor
Dim pdDisplay As System.ComponentModel.PropertyDescriptor
pdValue = cm.GetItemProperties()(Me.ValueMember)
pdDisplay = cm.GetItemProperties()(Me.DisplayMember)
myNewLeafNode = _
New TreeLeafNode(CStr(pdDisplay.GetValue(currObject)), _
currObject, _
pdValue.GetValue(currObject), _
currentListIndex)

  GetValue 在返回對(duì)象時(shí)忽略屬性的基本數(shù)據(jù)類型,因此在使用返回值前需要對(duì)其進(jìn)行轉(zhuǎn)換。

  保持?jǐn)?shù)據(jù)綁定控件同步

  CurrencyManager 還有一個(gè)主要功能:除了可以訪問(wèn)綁定數(shù)據(jù)源和項(xiàng)屬性外,它還允許使用相同的 DataSource 來(lái)協(xié)調(diào)該控件和任何其他控件之間的數(shù)據(jù)綁定。該支持可用于確保多個(gè)同時(shí)綁定到同一數(shù)據(jù)源的控件停留在數(shù)據(jù)源的同一項(xiàng)。對(duì)于我的控件而言,我想確保在樹(shù)中選擇項(xiàng)時(shí),其他所有綁定到同一數(shù)據(jù)源的控件均指向同一項(xiàng)(同一記錄、行、甚至數(shù)組,如果您愿意從數(shù)據(jù)庫(kù)的角度進(jìn)行思考)。為此,我覆蓋了基本 TreeView 中的 OnAfterSelect 方法。在該方法(在選擇樹(shù)節(jié)點(diǎn)后被調(diào)用)中,我將 CurrencyManager 對(duì)象的 Position 屬性設(shè)置為當(dāng)前選定項(xiàng)的索引。與該 TreeView 控件一起提供的示例應(yīng)用程序闡釋了同步控件如何使生成數(shù)據(jù)綁定用戶界面變得更為容易。為了使確定當(dāng)前選定項(xiàng)的列表位置更為容易,我使用了自定義 TreeNode 類(TreeLeafNodeTreeGroupNode),并將每個(gè)節(jié)點(diǎn)的列表索引存儲(chǔ)到創(chuàng)建的 Position 屬性中:

 

Protected Overrides Sub OnAfterSelect _
(ByVal e As System.Windows.Forms.TreeViewEventArgs)
Dim tln As TreeLeafNode
If TypeOf e.Node Is TreeGroupNode Then
tln = FindFirstLeafNode(e.Node)
Dim groupArgs As New groupTreeViewEventArgs(e)
RaiseEvent AfterGroupSelect(groupArgs)
ElseIf TypeOf e.Node Is TreeLeafNode Then
Dim leafArgs As New leafTreeViewEventArgs(e)
RaiseEvent AfterLeafSelect(leafArgs)
tln = CType(e.Node, TreeLeafNode)
End If

If Not tln Is Nothing Then
If cm.Position <> tln.Position Then
cm.Position = tln.Position
End If
End If
MyBase.OnAfterSelect(e)
End Sub

  在前面的代碼片段中,您可能注意到了一個(gè)稱為 FindFirstLeafNode 的函數(shù),在此我想對(duì)其加以簡(jiǎn)要介紹。在我的 TreeView 中,只有葉節(jié)點(diǎn)(分層結(jié)構(gòu)中的最終節(jié)點(diǎn))才與 DataSource 中的項(xiàng)相對(duì)應(yīng),其他所有節(jié)點(diǎn)只用于創(chuàng)建分組結(jié)構(gòu)。如果我要?jiǎng)?chuàng)建一個(gè)性能優(yōu)良的數(shù)據(jù)綁定控件,便始終需要選擇一個(gè)與 DataSource 相對(duì)應(yīng)的項(xiàng),因此每當(dāng)選擇組節(jié)點(diǎn)時(shí),我就會(huì)找到該組下的第一個(gè)葉節(jié)點(diǎn),就好象該節(jié)點(diǎn)是當(dāng)前的選定內(nèi)容。您可以檢查該示例的運(yùn)行情況,但現(xiàn)在您大可放心地使用它。

 

Private Function FindFirstLeafNode(ByVal currNode As TreeNode) _
As TreeLeafNode
If TypeOf currNode Is TreeLeafNode Then
Return CType(currNode, TreeLeafNode)
Else
If currNode.Nodes.Count > 0 Then
Return FindFirstLeafNode(currNode.Nodes(0))
Else
Return Nothing
End If
End If
End Function

  設(shè)置 CurrencyManager 對(duì)象的 Position 屬性可使其他控件與當(dāng)前選定項(xiàng)同步,但是當(dāng)其他控件的位置發(fā)生變化時(shí),CurrencyManager 也產(chǎn)生事件,以便相應(yīng)地更改選定項(xiàng)。要成為一個(gè)優(yōu)秀的數(shù)據(jù)綁定組件,所選內(nèi)容應(yīng)隨著數(shù)據(jù)源位置的更改而移動(dòng),修改某一項(xiàng)的數(shù)據(jù)時(shí),顯示應(yīng)隨之更新。CurrencyManager 引發(fā)的事件共有三個(gè):CurrentChanged、ItemChangedPositionChanged。最后一個(gè)事件相當(dāng)簡(jiǎn)單;CurrencyManager 的用途之一是為數(shù)據(jù)源維護(hù)當(dāng)前位置指示器,以便多個(gè)綁定控件均可以顯示同一記錄或列表項(xiàng),只要該位置更改,此事件便會(huì)引發(fā)。其他兩個(gè)事件有時(shí)會(huì)相互重疊,因而區(qū)別不太明顯。以下分別介紹如何在自定義控件中使用這些事件:PositionChanged 是一個(gè)比較簡(jiǎn)單的事件,此處不再贅述;當(dāng)您要在復(fù)雜數(shù)據(jù)綁定控件(如 Tree)中調(diào)整當(dāng)前選定項(xiàng)時(shí),請(qǐng)使用該事件。只要修改數(shù)據(jù)源中的項(xiàng),ItemChanged 事件就會(huì)引發(fā),而 CurrentChanged 只有在當(dāng)前項(xiàng)被修改時(shí)才引發(fā)。

  在我的 TreeView 中,我發(fā)現(xiàn)每當(dāng)我選擇一個(gè)新項(xiàng)時(shí),所有三個(gè)事件均會(huì)引發(fā),因此我決定通過(guò)更改當(dāng)前選定項(xiàng)來(lái)處理 PositionChanged 事件,而對(duì)另外兩項(xiàng)不進(jìn)行任何處理。建議將數(shù)據(jù)源強(qiáng)制轉(zhuǎn)換為 IBindingList(如果數(shù)據(jù)源支持 IBindingList 的話)并改用 ListChanged 事件,但我未實(shí)現(xiàn)此功能。

 

Private Sub cm_PositionChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles cm.PositionChanged
Dim tln As TreeLeafNode
If TypeOf Me.SelectedNode Is TreeLeafNode Then
tln = CType(Me.SelectedNode, TreeLeafNode)
Else
tln = FindFirstLeafNode(Me.SelectedNode)
End If

If tln.Position <> cm.Position Then
Me.SelectedNode = FindNodeByPosition(cm.Position)
End If
End Sub

Private Overloads Function FindNodeByPosition(ByVal index As Integer) _
As TreeNode
Return FindNodeByPosition(index, Me.Nodes)
End Function

Private Overloads Function FindNodeByPosition(ByVal index As Integer, _
ByVal NodesToSearch As TreeNodeCollection) As TreeNode
Dim i As Integer = 0
Dim currNode As TreeNode
Dim tln As TreeLeafNode

Do While i < NodesToSearch.Count
currNode = NodesToSearch(i)
i += 1
If TypeOf currNode Is TreeLeafNode Then
tln = CType(currNode, TreeLeafNode)
If tln.Position = index Then
Return currNode
End If
Else
currNode = FindNodeByPosition(index, currNode.Nodes)
If Not currNode Is Nothing Then
Return currNode
End If
End If
Loop
Return Nothing
End Function

   將 DataSource 轉(zhuǎn)變?yōu)闃?shù)

  編寫完數(shù)據(jù)綁定代碼后,我可以繼續(xù)添加管理分組級(jí)別的代碼,相應(yīng)地生成樹(shù),然后添加一些自定義事件、方法和屬性。

  管理組

  程序員要配置組集合,就必須創(chuàng)建 AddGroup、RemoveGroupClearGroups 函數(shù)。每當(dāng)修改組集合時(shí),都必須重新繪制樹(shù)(以反映新配置),因此我創(chuàng)建了一個(gè)通用過(guò)程 GroupingChanged,當(dāng)情況發(fā)生變化,需要強(qiáng)制重建樹(shù)時(shí),它可以由控件中的各種代碼調(diào)用:

 

Private treeGroups As New ArrayList()

Public Sub RemoveGroup(ByVal group As Group)
If Not treeGroups.Contains(group) Then
treeGroups.Remove(group)
GroupingChanged()
End If
End Sub

Public Overloads Sub AddGroup(ByVal group As Group)
Try
treeGroups.Add(group)
GroupingChanged()
Catch
End Try
End Sub

Public Overloads Sub AddGroup(ByVal name As String, _
ByVal groupBy As String, _
ByVal displayMember As String, _
ByVal valueMember As String, _
ByVal imageIndex As Integer, _
ByVal selectedImageIndex As Integer)
Dim myNewGroup As New Group(name, groupBy, _
displayMember, valueMember, _
imageIndex, selectedImageIndex)
Me.AddGroup(myNewGroup)
End Sub


Public Function GetGroups() As Group()
Return CType(treeGroups.ToArray(GetType(Group)), Group())
End Function


  生成樹(shù)

  樹(shù)的實(shí)際重建由一對(duì)過(guò)程來(lái)完成:BuildTreeAddNodes。由于這兩個(gè)過(guò)程的代碼太長(zhǎng),本文并未全部列出,而是盡量概括它們的行為(當(dāng)然,如果愿意您可以下載完整的代碼)。如前所述,程序員可以通過(guò)設(shè)置一系列組與該控件進(jìn)行交互,然后在 BuildTree 中使用這些組來(lái)確定如何設(shè)置樹(shù)節(jié)點(diǎn)。BuildTree 清除當(dāng)前節(jié)點(diǎn)集合,然后遍歷整個(gè)數(shù)據(jù)源來(lái)處理第一級(jí)分組(本文前面的示例和圖解中提到的 Publisher),為每個(gè)不同的分組值添加一個(gè)節(jié)點(diǎn)(使用示例中的數(shù)據(jù),為每個(gè) pub_id 值添加一個(gè)節(jié)點(diǎn)),然后調(diào)用 AddNodes 來(lái)填充第一級(jí)分組下的所有節(jié)點(diǎn)。AddNodes 遞歸調(diào)用自身以處理任意多的級(jí)數(shù),必要時(shí)可添加組節(jié)點(diǎn)和葉節(jié)點(diǎn)。使用兩個(gè)基于 TreeNode 的自定義類以區(qū)別組節(jié)點(diǎn)和葉節(jié)點(diǎn),并為兩類節(jié)點(diǎn)提供各自相應(yīng)的屬性。

  自定義 TreeView 事件

  每當(dāng)選擇一個(gè)節(jié)點(diǎn)時(shí),TreeView 都會(huì)引發(fā)兩個(gè)事件:BeforeSelectAfterSelect。但在我的控件中,我想使組節(jié)點(diǎn)和葉節(jié)點(diǎn)的事件不同,于是便添加了自己的事件 BeforeGroupSelect/AfterGroupSelectBeforeLeafSelect/AfterLeafSelect,除基本事件外,還引發(fā)了自定義事件參數(shù)類:

 

Public Event BeforeGroupSelect _
(ByVal sender As Object, ByVal e As groupTreeViewCancelEventArgs)
Public Event AfterGroupSelect _
(ByVal sender As Object, ByVal e As groupTreeViewEventArgs)
Public Event BeforeLeafSelect _
(ByVal sender As Object, ByVal e As leafTreeViewCancelEventArgs)
Public Event AfterLeafSelect _
(ByVal sender As Object, ByVal e As leafTreeViewEventArgs)

Protected Overrides Sub OnBeforeSelect _
(ByVal e As System.Windows.Forms.TreeViewCancelEventArgs)
If TypeOf e.Node Is TreeGroupNode Then
Dim groupArgs As New groupTreeViewCancelEventArgs(e)
RaiseEvent BeforeGroupSelect(CObj(Me), groupArgs)
ElseIf TypeOf e.Node Is TreeLeafNode Then
Dim leafArgs As New leafTreeViewCancelEventArgs(e)
RaiseEvent BeforeLeafSelect(CObj(Me), leafArgs)
End If
MyBase.OnBeforeSelect(e)
End Sub

Protected Overrides Sub OnAfterSelect _
(ByVal e As System.Windows.Forms.TreeViewEventArgs)
Dim tln As TreeLeafNode
If TypeOf e.Node Is TreeGroupNode Then
tln = FindFirstLeafNode(e.Node)
Dim groupArgs As New groupTreeViewEventArgs(e)
RaiseEvent AfterGroupSelect(CObj(Me), groupArgs)
ElseIf TypeOf e.Node Is TreeLeafNode Then
Dim leafArgs As New leafTreeViewEventArgs(e)
RaiseEvent AfterLeafSelect(CObj(Me), leafArgs)
tln = CType(e.Node, TreeLeafNode)
End If

If Not tln Is Nothing Then
If cm.Position <> tln.Position Then
cm.Position = tln.Position
End If
End If
MyBase.OnAfterSelect(e)
End Sub

  自定義節(jié)點(diǎn)類(TreeLeafNodeTreeGroupNode)和自定義事件參數(shù)類均包括在可下載代碼中。

  示例應(yīng)用程序

  要全面理解本示例控件中的所有代碼,您應(yīng)該了解它在應(yīng)用程序中的運(yùn)行情況。包含的示例應(yīng)用程序使用 pubs.mdb Access 數(shù)據(jù)庫(kù),并說(shuō)明 Tree 控件如何與其他數(shù)據(jù)綁定控件一起創(chuàng)建 Windows 應(yīng)用程序。本例中,尤其值得注意的主要功能包括樹(shù)與其他綁定控件的同步以及對(duì)數(shù)據(jù)源執(zhí)行搜索時(shí)樹(shù)節(jié)點(diǎn)的自動(dòng)選擇。

注意:本示例應(yīng)用程序(名為“TheSample”)包含在本文的下載中。

圖 4:數(shù)據(jù)綁定 TreeView 的演示應(yīng)用程序

  小結(jié)

  本文介紹的數(shù)據(jù)綁定 Tree 控件并非適用于所有需要 Tree 控件來(lái)顯示數(shù)據(jù)庫(kù)信息的項(xiàng)目,但它確實(shí)介紹了一種可針對(duì)個(gè)人目的自定義該控件的方法。請(qǐng)記住,您要生成的任何復(fù)雜數(shù)據(jù)綁定控件與 Tree 控件的大部分代碼基本相同,您可以通過(guò)修改現(xiàn)有代碼來(lái)簡(jiǎn)化以后的控件開(kāi)發(fā)過(guò)程。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产精品入口麻豆高清| 国产免费一区二区三区在线能观看| 国产欧美精品日韩| 成人精品999| 日本在线观看a| 国产精品久久久久影院| 欧美精品一区在线观看| 理论片影音先锋| 色综合天天综合网国产成人网| 国产美女作爱全过程免费视频| 久久久久久无码午夜精品直播| 黄色精品视频网站| 国产精品久久久久一区| 亚洲精品国产suv一区| 欧美视频二区欧美影视| 亚洲精品综合| av网站在线免费看| 亚洲第一在线视频| 美女激情网站| 黄色av免费在线观看| a篇片在线观看网站| 欧美女人交a| 亚洲黄色小说视频| 欧美老熟妇乱大交xxxxx| 杨幂一区二区国产精品| 成年女人的天堂在线| 亚洲免费av一区二区三区| 久久在线免费观看| 秋霞影视一区二区三区| 欧美日韩中文字幕在线视频| 看欧美ab黄色大片视频免费| 欧美日本在线视频| 91麻豆国产在线观看| 欧美丝袜一区二区三区| 久久这里只有精品一区二区| 久久久久久国产| 国产人成网在线播放va免费| 国产chinasex对白videos麻豆| 狠狠色噜噜狠狠狠888奇米| 亚洲三级免费观看| 亚洲最新av网址| 国产黄色一区| 97久久人人超碰caoprom| 亚洲欧美日韩人成在线播放| 亚洲丝袜精品丝袜在线| 亚洲欧洲国产精品久久| 国产福利电影网| 九九久久精品| 欧美日本亚洲| 无码国精品一区二区免费蜜桃| 不卡一区二区在线| www.91在线播放| 精品久久久免费视频| 97人妻精品一区二区三区| 日韩av电影免费观看| 精品伊人久久久| 日韩欧美黄色大片| 在线观看中文字幕| 精品久久ai| 欧美喷水一区二区| 久久99精品波多结衣一区| www黄色日本| 国产成人精品久久| 免费看美女视频在线网站| www黄色在线观看视频| 国产黄色片在线播放| 中文高清一区| 亚洲成年人视频| 国产一区二区三区在线观看免费| 国产一区二区在线免费观看| 中文字幕在线不卡一区二区三区| 久久国内精品自在自线400部| 成人精品鲁一区一区二区| 欧美性猛片xxxx免费看久爱| 国产精品久久久久久久久免费看| 97超级碰碰碰| 国产高清精品二区| 欧美一区二区三区色| 免费h网站在线观看| a毛片毛片av永久免费| 手机免费看av网站| 久久99久久99精品免视看婷婷| 亚洲成a人片777777久久| 中文字幕中文字幕在线中高清免费版| √资源天堂中文在线| 国产嫩草在线视频| 日韩在线观看www| 天天做夜夜做人人爱精品| 在线精品自拍| 又大又硬又爽免费视频| 自拍偷拍精品视频| 四虎影视国产在线视频| 天天操天天插| 999国产精品亚洲77777| 精品国内自产拍在线观看视频| 2018高清国产日本一道国产| 欧美伦理91i| 国产一区二区在线|播放| av资源在线看| 国产伦精品一区二区三区四区免费| 一本一本久久a久久精品综合麻豆| 中文字幕最新精品| 欧美亚州一区二区三区| 日本99精品| 国产亚洲aⅴaaaaaa毛片| 国产亚洲精品码| 精品无码一区二区三区的天堂| 亚洲第一精品夜夜躁人人爽| 国内精品免费**视频| 精品欧美日韩一区二区| 国产成人精品福利一区二区三区| 国产精品v日韩精品| 欧美伊人精品成人久久综合97| 欧美片网站yy| 日韩在线视频免费播放| 国产中文字幕精品| 任我爽在线视频精品一| 七七婷婷婷婷精品国产| 天天夜夜亚洲| 午夜在线一区| 中老年在线免费视频| 欧美午夜视频一区二区| 国产九色精品| 久久男人av| 亚洲电影二区| 国产成人欧美在线观看| 免费91在线视频| 国产婷婷色一区二区在线观看| 九九视频在线播放| 亚洲国产日韩欧美在线动漫| 蜜臀一区二区三区精品免费视频| 亚洲av无码一区二区乱子伦| 亚洲精品丝袜日韩| 91一区二区视频| 嫩草懂你的影院| av成人免费观看| 亚洲综合一区二区精品导航| 波多野结衣一区二区三区免费视频| 伊人一区二区三区| 自拍偷拍亚洲天堂| 久久久久久久性| 91免费电影网站| 99热国内精品| 污视频网站在线| 在线成人激情视频| 亚洲二区在线播放| 亚洲夜间福利| 潮喷失禁大喷水aⅴ无码| 亚洲激情社区| 欧美喷潮久久久xxxxx| 自拍偷拍视频在线| 免费又爽又黄禁片视频1000片| 国产一区二区剧情av在线| 精品人妻少妇AV无码专区| 亚洲怡红院在线观看| 电影在线观看一区二区| 97超碰在线资源站| 成人av在线播放| 人妻av一区二区| 国产91av视频在线观看| 日韩精品欧美专区| 久久gogo国模啪啪裸体| 国产一区二区在线观| 香蕉精品视频在线| 精品在线手机视频| 亚洲黄色高清| 日本韩国视频一区二区| 亚洲婷婷综合久久一本伊一区| 成人在线激情视频| 国语自产精品视频在线看一大j8| 九一国产精品视频| 国产视频一区在线观看一区免费| 中文精品视频一区二区在线观看| 日韩大尺度黄色| 91看片在线播放| 在线观看国产精品淫| av网站在线免费看推荐| 国产人伦精品一区二区| 午夜久久美女| 成人免费观看网址| 精品国产91亚洲一区二区三区婷婷| www欧美在线| 456亚洲精品成人影院| 影视先锋av资源站| 午夜影院在线观看国产主播| 国产精品中文字幕日韩精品| 黄色性生活一级片| 日韩三级精品电影久久久| 国产三区视频在线观看| 国产成人啪午夜精品网站男同| 依依成人在线视频| 久久久噜噜噜www成人网| 国产a国产a国产a| 日韩欧美中文在线观看| 中文字幕在线观看一区二区三区| av在线中文| 亚洲视频免费在线观看| 国产精品免费久久久久| 欧美xxxooo| 成人免费毛片app| 中文字幕在线一区二区三区| 国产香蕉成人综合精品视频| av小片在线| 久久夜色邦福利网| 5566av亚洲| 国产在线电影| 91精品综合久久久久久久久久久| 国产精品欧美一区喷水| 久久久久久电影| 黑人操日本美女| 久久精品免费av| 国产日韩一区二区三区在线| 国产日韩专区在线| av毛片在线播放| 国产精品成熟老女人| 中文字幕在线观看91| 欧美怡红院视频一区二区三区| 日本老师69xxx| 超碰97人人在线| 中文字幕精品在线观看| 亚洲综合另类小说| 黄视频在线播放| 欧美xxxxxxxx| 色八戒一区二区三区| 午夜精品一区二区三区免费视频| 怡红院视频网站| 在线视频日韩| 玖玖在线免费视频| 91精品国产免费久久综合| 日本黄视频网站| 明星裸体视频一区二区| 丰满放荡岳乱妇91ww| 无码国产精品久久一区免费| 免费网站黄在线观看| 国产剧情久久久久久| 欧美 日韩 国产 成人 在线| 久久久久久电影| 97久久精品| 成人网在线免费看| 免费人成黄页网站在线一区二区| 欧美乱大交xxxxx潮喷l头像| 色综合免费视频| 一区二区三区精品视频在线观看| 欧美一区电影| 夜夜精品浪潮av一区二区三区| 模特精品在线| 日韩欧美黄色网址| 日韩视频在线免费| 久久综合一区二区三区| 国产性网软件大全| 久久久久久免费观看| 亚洲欧洲第一视频| 18岁免费网站| 色呦呦网站入口| 日本伊人午夜精品| 精品人妻无码一区二区| 久久婷婷五月综合色国产香蕉| 99re精彩视频| 一本色道久久综合狠狠躁的番外| 天天综合天天操| 亚洲精品亚洲人成在线观看| 麻豆成人久久精品二区三区红| 色综合视频一区二区三区44| 国产丝袜在线播放| 日本亚洲免费观看| 国产精品一区二区久久精品爱涩| 欧美五码在线| 国卡一卡二卡三免费网站| 精品1卡二卡三卡四卡老狼| 手机在线色视频| 精品97人妻无码中文永久在线| 国产视频一视频二| 国产一级揄自揄精品视频| 风间由美中文字幕在线看视频国产欧美| 亚洲色图第三页| 五月天电影免费在线观看一区| 在线一区二区日韩| 888av在线| 欧美日韩成人激情| 国产一区二区在线视频你懂的| 中文字幕免费不卡| 91免费黄视频| 亚洲欧洲高清在线| 亚洲综合日韩欧美| 欧美有码在线| 欧美videosex性欧美黑吊| 一二三四视频社区在线| 日韩亚洲欧美在线| av不卡一区二区三区| 日韩免费一区二区三区| 成人福利视频导航| 91大神福利视频在线| 天天干天天操天天干天天操| 奇米色欧美一区二区三区| 国产女主播喷水视频在线观看| 欧美日韩在线精品一区二区三区| 免费不卡在线观看| 成 人 黄 色 片 在线播放| 麻豆亚洲av熟女国产一区二| 黄色三级中文字幕| 中文字幕佐山爱一区二区免费| 国产高清免费在线播放| 黄色一区三区| aaaaaaa大片免费看| 真实原创一区二区影院| 日韩在线视频免费播放| 日韩**中文字幕毛片| 国产精品永久免费在线| 日韩av日韩在线观看| 国产1区2区3区精品美女| 国产午夜精品视频一区二区三区| 欧美高清成人| 四虎精品成人a在线观看| 欧美日韩人妻精品一区在线| 免费午夜一级| 天天看天天干| 97看剧电视剧大全| 欧美日韩一级在线| 日韩一级片免费在线观看| 亚洲不卡在线观看| 久久久精品国产sm调教| 永久久久久久久| 91视频国产一区| 丝袜美腿亚洲一区二区图片| 国产午夜精品一区理论片飘花| 色综合久久一区二区三区| 久草在线资源站手机版| 欧美性生活大片视频|