MCCB - 多列组合框 - 如何创建简单的(用户控件)DLL






4.70/5 (14投票s)
回想第一次,在我已经是一名 VB 和 VBA 的资深程序员时,我感到有必要构建我的第一个可重用 DLL。
首先
CodeProject 面向所有级别的程序员。本文档 **仅** 供从未构建过 DLL 的初学者和 VB 程序员阅读。有关更复杂的组合框,请参阅我的第一篇文章: ExCB - 扩展多列组合框
引言
下载的文件包含完整的项目,但我将展示创建此控件的基本步骤,该控件是一个能够永久显示一列或多列(例如“字段框”,带标签或不带标签)以及用于“记录”选择的列表的组合框。
DLL 通常是一个控件,由用户为特定目的创建的其他 System.Windows.Form 控件组成,通常灵活、可参数化,并准备好执行各种任务。
与其他控件一样,**UserControl** 具有自己的 **属性**、**方法** 和 **事件**,其中一些是我们自己创建的。
在开发 DLL 时,最好有一个另一个简单的 WinForms 项目来测试控件,这两个项目都在一个 **解决方案** 中,以便我们可以深入测试和调试控件的行为。
构建用户控件
- 打开 **Visual Studio**,启动 **新项目**,选择 **类库** 并将其命名为 **MCCB**,这将是项目名称、程序集名称和根命名空间 - 但 VS 会给你一个 VB **Public Class Class1**
- 菜单 **PROJECT**,选择 **Add User Control** 并将其命名为 **MCCB**,这将是您控件的未来名称 - VS 会创建另一个类并显示模板 - 一个 150x150 的正方形,更像一个 Panel 而不像一个 Form...
在此示例中,目标是创建一个组合框,该组合框公开一列或多列,并带有标签。我们创建第一列,所有其他列将在运行时创建。我们还需要一个下拉列表和一个用于打开列表的按钮。
- **调整** 控件的大小至约 200x200 并将其 **BackColor** 更改为其他(略微不同)的颜色。在运行时,此颜色将更改为 **Color.Control**,但在设计时我们需要一个视觉参考,在调整控件大小时。
- 让我们从标签(标题/标题栏)开始:从 **Toolbox** 中选择一个 **Label**。更改以下属性:Name="**Hdr0**",AutoSize=**False**,BackColor=**WhiteSmoke**,BorderStyle=**FixedSingle**,Location=**0;0**,Size=**100;19**,Text="**Hdr0**",TextAlign=**MiddleLeft**
- 现在是显示字段值的框。我们不使用 TextBox,而是使用 Label... 它是一个更轻量级的控件,而且值不打算被写入或更改。选择另一个 **Label** 并更改以下属性:Name="**Box0**",AutoSize=**False**,BackColor=**White**,BorderStyle=**FixedSingle**,ForeColor=**Navy**,Location=**0;18**,Size=**100;20**,Text="**Box0**",TextAlign=**MiddleLeft**
- 接下来是列表。选择一个 **ListView** 并更改属性:Name="**MyLV**",View=**Details**,BorderStyle=**FixedSingle**,FullRowSelect=**True**,GridLines=**True**,HeaderStyle=**None**,Location=**0;37**,MultiSelect=**False**,Size=**119;138**。这是一个有 8 行的列表,没有标题... 我们还将创建第一列:添加一个 **Column** 并更改属性:Name="**lvCol0**",Text=" ",Width=**97**。为什么是 97?为了完美地对齐行,ListView 列的宽度必须是相应标签/框宽度的减 1,第一个列除外,它必须是减 3...
- 最后是按钮,它必须显示任何种类的“向下箭头”。它可以是按钮、PictureBox,甚至是简单的 Label。我们用 Label 来做。选择一个 **Label** 并更改属性:Name="**LblDrop**",AutoSize=**False**,BackColor=**WhiteSmoke**,BorderStyle=**FixedSingle**,Location=**99;18**,Size=**20;20**,Text=" "。在属性 Image - Local resource - Import:**DArrow.png**,位于文件夹 **.\Image**
- 一切都 OK 并对齐了,对吗?但当控件放置在 Form 上时,列表必须隐藏... 因此,为了防止设计时垂直调整大小,并且因为标题+框的实际高度是 **38**,请在此用户控件的 **Resize Event** 中添加这个最开始的代码。
Private Sub MCCB_Resize(sender As Object, e As EventArgs) Handles Me.Resize
Me.Height = 38
End Sub
- 现在是时候创建用于测试和调试控件的项目了。**保存** 项目并启动一个类型为 **Windows Forms Application** 的 **新项目**,将其命名为 **MCCB_Test** - VS 会给你一个 Form 模板(Form1)。**保存** 这个第二个项目。
- 添加用户控件项目:菜单 **FILE** - **Add** - **Existing Project** - 浏览 MCCB 项目并打开 *MCCB.vbproj* - 将创建一个名为 '**MCCB_Test**' 的解决方案,其中包含 Solution Explorer 中的两个项目。**选择** MCCB 项目,菜单 **BUILD** - **Build MCCB**。打开 Toolbox 并查看顶部... MCCB 控件已经在那儿了。**双击** 它 - 控件将被放置在 Form 上,名称为 **Mccb1**。**调整** 大小 - 如你所见,只允许水平调整大小。**启动** 解决方案 - **太棒了,控件在那儿!!!** 现在你可以管理这两个项目了。插入一段代码,菜单 **BUILD** - **Rebuild MCCB**,如果需要,在 Form1 中检查或更改控件属性,如果需要,设置断点进行调试,然后**启动** 解决方案。很简单。
我们即将创建一组 **属性**。通常,属性必须是 **Public** 并指定其数据类型。自定义属性的值可以像 IDE 属性窗口中的任何其他属性一样查看和更改,或在运行时更改。我们的大部分属性,除了一个,都可能在 IDE 属性窗口中读取和修改。其中一些会改变控件的外观:标题/框的 **高度**、**边框样式**、标题/框/列表的 **前景色** 和 **背景色**。这些属性意味着控件需要 重绘,我们稍后会看到。它们具有定义好的数据类型 - Integer、Byte、Color、BorderStyle - 可以使用预定义的对话框、组合框或文本框进行更改。但是,尽管属性 ListFontStyle
和 LayerOrder
处理的是 Byte 值,但我们宁愿使用一个带有描述性文本的组合框来表示允许的值,而不是一个简单的文本框来输入数字。为此,我们必须声明我们 **Enum**eration 列表的数据类型。最后,属性 SelectedIndex
仅在运行时使用,即必须不可浏览且隐藏。在此 处 查看所有属性。
- 选择并打开 *MCCB.vb* 代码选项卡。让我们 **导入** 一个引用,这是指定一些属性属性所必需的,例如 Category、Description、Browsable 或 DesignerSerializationVisibility,并声明两个 **Enum** 类型和几个 **变量** - 一些用于属性值(变量的
_Name
是属性的 **Name**,前面加下划线),一些用于内部使用。
Imports System.ComponentModel ' For PropertyAttributes
Public Class MCCB
Public Enum LFStyle ' for Property ListFontStyle
SameAsControl = 0
AlwaysRegular = 1
End Enum
Public Enum LayOrder ' for Property LayerOrder
Normal = 0
BringToFront = 1
SendToBack = 2
End Enum
' Property variables
Private _MaxItemsDisp As Integer = 8
Private _HeaderHeight As Byte = 19
Private _HeaderBackColor As Color = Color.WhiteSmoke
Private _HeaderForeColor As Color = Color.Black
Private _HeaderBorderStyle As BorderStyle = Windows.Forms.BorderStyle.FixedSingle
Private _BoxHeight As Byte = 20
Private _BoxBackColor As Color = Color.White
Private _BoxForeColor As Color = Color.MediumBlue
Private _BoxBorderStyle As BorderStyle = Windows.Forms.BorderStyle.FixedSingle
Private _ListBackColor As Color = Color.White
Private _ListForeColor As Color = Color.Black
Private _ListBorderStyle As BorderStyle = Windows.Forms.BorderStyle.FixedSingle
Private _ListFontStyle As Byte = 0 ' 0-SameAsControl, 1-AlwaysRegular
Private _LayerOrder As Byte = 0 ' 0-Normal, 1-BringToFront, 2-SendToBack
Private _SelectedIndex As Integer = -1
' Internal variables
Private _ColumnCount As Integer = 0
Private _ColumnIndex As Integer = 0
Private _TotalWidth As Integer = 99
Private _LeftLocation As Integer = 0
Private _ItemsCount As Integer = 0
Private _Me_MinHeight As Integer = _HeaderHeight + _BoxHeight - 1
Private _ListHeight As Integer = 0
Private _ShowList As Boolean = False ' used in Resize event
Private _FNIlastIdx As Integer = -1 ' Last ColumnIndex searched
Private _FNIlastStr As String = "" ' Last String searched
Private _FNI_iFrom As Integer = -1
Private _Error As String = "Error"
- 如前所述,大多数属性都意味着控件需要 **重绘**。重绘控件意味着 Resize 事件将被触发。每当列表下拉或隐藏时,即当“按钮”**LblDrop** 被点击时,Resize 事件也将被调用。所以,Resize 事件必须处理两种不同的情况:1)列表要下拉(如果显示的项目),具有正确的 [高度]。2)列表要隐藏。为了控制其行为,我们创建了一个变量
_ShowList
,其初始值为False
,从而确保设计模式下的正确缩放。因此,让我们更改用户控件的 **Resize Event**。请注意,_Me_MinHeight = _HeaderHeight + _BoxHeight - 1
,因此_Me_MinHeight
始终代表控件的(最小)高度,不含列表,列表的高度是显示的行数,每行 **17** 像素 [16(行高)+ 1(分隔线)] 加上 **1**(最后一行)。
Private Sub MCCB_Resize(sender As Object, e As EventArgs) Handles Me.Resize
'Me.Height = 38 ' Replaced by the code below:
If _ShowList And _ItemsCount > 0 Then
_ListHeight = Math.Min(_ItemsCount, _MaxItemsDisp) * 17 + 1
Else
_ListHeight = 0
End If
Me.Height = _Me_MinHeight + _ListHeight
MyLV.Height = _ListHeight
End Sub
- Resize 事件(也)将从其他几个情况被调用,但变量
_ShowList
必须设置为所需值。因此,让我们创建一个唯一的 Sub,它设置变量的值并调用 Resize 事件,该事件将在所有这些情况下被调用。
Private Sub ShowHideList(Show As Boolean)
_ShowList = Show
MCCB_Resize(Nothing, Nothing)
End Sub
- 现在,让我们提供一个机制来下拉或隐藏列表,当标签 **LblDrop** 被点击时。更重要的是,当鼠标悬停在标签上时,它的
BackColor
变为Orange
,并且Cursor
变为Hand
。因此,让我们使用MouseHover
、MouseLeave
和Click
事件。
Private Sub LblDrop_MouseHover(sender As Object, e As EventArgs) Handles LblDrop.MouseHover
Me.Cursor = Cursors.Hand
sender.BackColor = Color.Orange
End Sub
Private Sub LblDrop_MouseLeave(sender As Object, e As EventArgs) Handles LblDrop.MouseLeave
Me.Cursor = Cursors.Default
sender.BackColor = Color.WhiteSmoke
End Sub
Private Sub LblDrop_Click(sender As Object, e As EventArgs) Handles LblDrop.Click
ShowHideList(Show:=(Me.Height <= _Me_MinHeight))
End Sub
- 现在是创建我们第一个 **Property** 的时候了。默认情况下,属性是可读的(**Get** 部分)和可写的(**Set** 部分)。但是,它们也可以声明为 **ReadOnly**(仅 Get 部分)或 **WriteOnly**(仅 Set 部分)。此外,还可以指定一些属性。在这种情况下,
Category
(现有或新创建的,属性将被包含在其中)和Description
(出现在属性窗口底部的说明)。要读取属性,请 **Return** 相关变量的值。要写入属性,请将相关变量 **set** 为指定的值 **value**,如果值要立即生效,请编写相应的操作。在这种情况下,只需调用 SubShowHideList
,并带有参数True
,以设置变量_ShowList
并**下拉**列表。
<Category("_MCCB specifics")> _
<Description("Maximum Items Displyed by the List")> _
Public Property MaxItemsDisp() As Byte
Get
' Get - if the Property is readable (or ReadOnly)
Return _MaxItemsDisp
End Get
Set(ByVal value As Byte)
' Set - if the Property is writable (or WriteOnly)
_MaxItemsDisp = value
ShowHideList(True) ' Action
End Set
End Property
- 目前,让我们创建我们的第一个 **Method**,它允许添加列并设置一些(固定)属性。为了从外部访问,Method 必须是 **Public**。第一次调用此 Method 时,不会创建新列,而是更改已存在的列。Method 将接受三个参数。
- **Width** - 必需。列的宽度(以像素为单位)。值为 **0** 将创建一个隐藏的列。
- **Text** - 必需。列的标题(Header)。
- **Align** - 可选。列的水平对齐方式。默认(如果不指定)为左对齐。HorizontalAlignment 值(0=Left,1=Right,2=Center)用于定义 ListView 列(或例如 TextBoxes)的 TextAlign 属性。但是,**Labels** 使用其他值(ContentAlignment),除了水平位置外,还反映了垂直位置(Top、Middle、Bottom)。我们的“Headers”和“Boxes”需要“Middle”对齐,因此 HorizontalAlignment 值(0、1 和 2)必须转换为“Middle”ContentAlignment 值(分别为 16、64 和 32)。
Public Sub AddColumn(Width As Integer, Text As String, _
Optional Align As HorizontalAlignment = 0)
Dim Lbl_Align As ContentAlignment = If(Align = 1, 64, _
If(Align = 2, 32, 16))
Dim Hdr As Label
Dim Box As Label
Me.SuspendLayout()
_ColumnCount += 1
_ColumnIndex = _ColumnCount - 1
If _ColumnCount = 1 Then ' First Column, already exists
Hdr = Hdr0 ' Existing Header
Box = Box0 ' Existing Box
MyLV.Width = Width + 19 ' Existing List. Initial
' value, including the "Button" (LblDrop)
lvCol0.Width = Width - 3 ' Existing ListView Column
_TotalWidth = Width - 1 ' Initial value
Me.BackColor = Color.Transparent
Else ' Column is to be created
Hdr = New Label ' New Header
Hdr.Name = "Hdr" & _ColumnIndex.ToString
Hdr.Left = _TotalWidth
Box = New Label ' New Box
Box.Name = "Box" & _ColumnIndex.ToString
Box.Left = _TotalWidth
MyLV.Columns.Add(New ColumnHeader) ' New ListView Column
MyLV.Columns(_ColumnIndex).Name = "lvCol" & _ColumnIndex.ToString
MyLV.Columns(_ColumnIndex).Text = ""
MyLV.Columns(_ColumnIndex).Width = Math.Max(Width - 1, 0)
MyLV.Columns(_ColumnIndex).TextAlign = Align
MyLV.Width += Width - 1 ' Accum.
_TotalWidth += Width - 1 ' Accum.
End If
Hdr.Width = Width ' Header
Hdr.Text = Text
Hdr.TextAlign = Lbl_Align
Box.Width = Width ' Box
Box.Text = ""
Box.TextAlign = Lbl_Align
LblDrop.Left = _TotalWidth ' DropDown "Button"
LblDrop.Height = _BoxHeight
If _ColumnCount > 1 Then ' All but first
Controls.AddRange({Box, Hdr})
End If
Me.ResumeLayout(True)
RedrawControls()
End Sub
调用此 Method 的示例
Mccb1.AddColumn(140, "Name") ' Align not specified = HorizontalAlignment.Left
Mccb1.AddColumn(35, "Age", HorizontalAlignment.Center)
Mccb1.AddColumn(90, "Due date", 2) ' 2 = HorizontalAlignment.Center
Mccb1.AddColumn(90, "Amount (US$)", HorizontalAlignment.Right)
- 如前所述,
AddColumn
Method 创建新列,设置其不可更改的属性。但为了正确完成组件设置,我们必须初始化可以随时更改的属性。因此,我们将创建一个特定的(**Private**)**Sub**routine(RedrawControls
),它也由AddColumn
Method 调用(最后一条指令):请注意,由于控件的大小已更改(Me.Height
&Me.Width
),控件的Resize
Event 将被触发。
Private Sub RedrawControls()
Me.SuspendLayout()
MyLV.Top = _HeaderHeight + _BoxHeight - 2
MyLV.BackColor = _ListBackColor
MyLV.ForeColor = _ListForeColor
MyLV.BorderStyle = _ListBorderStyle
Dim Name As String
For iCtr As Integer = 0 To _ColumnIndex ' For each Column...
Name = "Box" & iCtr.ToString
Controls(Name).Top = _HeaderHeight - 1
Controls(Name).Height = _BoxHeight
Controls(Name).BackColor = _BoxBackColor
Controls(Name).ForeColor = _BoxForeColor
Dim Lbl As Label = CType(Controls(Name), Label)
Lbl.BorderStyle = _BoxBorderStyle
Name = "Hdr" & iCtr.ToString
Controls(Name).Height = _HeaderHeight
Controls(Name).BackColor = _HeaderBackColor
Controls(Name).ForeColor = _HeaderForeColor
Lbl = CType(Controls(Name), Label)
Lbl.BorderStyle = _HeaderBorderStyle
Next
LblDrop.Top = _HeaderHeight - 1
LblDrop.Height = _BoxHeight
_Me_MinHeight = _HeaderHeight + _BoxHeight - 1
Me.Height = _Me_MinHeight
Me.Width = _TotalWidth + 20 ' 20=LblDrop.Width
Me.ResumeLayout(True)
End Sub
- 查看提供的源项目。复制或复制所有其他调用
RedrawControls
的属性。特别注意两个操作不同的属性:第一个是ListFontStyle
,其类型由 EnumLFStyle
定义,它设置变量_ListFontStyle
并调用 Event(FontChanged
),该 Event 在字体更改时发生。第二个是LayerOrder
,其类型由 EnumLayOrder
定义,它设置变量_LayerOrder
,但其操作会提前进行,取决于其先前的值。为什么?因为,如果 a 和 b 没有疑问,将值设置为 0(Normal)意味着改变最后一个行为。该操作也必须在控件加载时在控件的 **Load Event** 中执行。让我们看看Load
和FontChanged
事件,以及这两个属性。
Private Sub MCCB_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If _LayerOrder = 1 Then
Me.BringToFront()
ElseIf _LayerOrder = 2 Then
Me.SendToBack()
End If
End Sub
Private Sub MCCB_FontChanged(sender As Object, e As EventArgs) Handles Me.FontChanged
MyLV.Font = New Font(Me.Font, If(_ListFontStyle = 0, _
Me.Font.Style, FontStyle.Regular))
End Sub
<Category("_MCCB specifics")> _
<Description("Action in List when Control's Font changes to Bold")> _
Public Property ListFontStyle() As LFStyle
Get
Return _ListFontStyle
End Get
Set(ByVal value As LFStyle)
_ListFontStyle = value
MCCB_FontChanged(Nothing, Nothing)
End Set
End Property
<Category("_MCCB specifics")> _
<Description("Control's Layer Order Action")> _
Public Property LayerOrder() As LayOrder
Get
Return _LayerOrder
End Get
Set(ByVal value As LayOrder)
If value = 1 OrElse (value = 0 And _LayerOrder = 2) Then
Me.BringToFront()
ElseIf value = 2 OrElse (value = 0 And _LayerOrder = 1) Then
Me.SendToBack()
End If
_LayerOrder = value
End Set
End Property
- 让我们创建一个 Method 来填充列表。它需要一个 **字符串数组**,每个 SubItem 一个,包括任何隐藏的列。很简单,因为这样的数组可以直接转换为所需的
ListViewItem
类型。它返回一个Boolean
,指示操作的成功(True
)或失败(False
)。
Public Function AddRow(SubItems As Array) As Boolean
Dim OK As Boolean = False
If SubItems.Length > _ColumnIndex + 1 Then
MsgBox("SubItems (" & SubItems.Length.ToString & _
") exceeds the number of Columns (" & _
(_ColumnIndex + 1).ToString & ")...", _
MsgBoxStyle.Critical, _Error)
Else
Try
MyLV.Items.Add(New ListViewItem(SubItems))
_ItemsCount += 1
OK = True
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, _Error)
End Try
End If
Return OK
End Function
调用此 Method 的示例
Dim vAge As Byte = 35
Dim vDate As String = Today.ToShortDateString
Dim vValue As Single = 1234.56
If Mccb1.AddRow({"John Smith", vAge.ToString, vDate, Format(vValue, "#,###.00")}) = False Then
' Something went wrong...
End If
- 当选择列表行时,该行的 **SubItem(s)** 必须显示在相应的 **Box(es)** 中。为了执行此任务,让我们创建一个 Sub
ShowSelectedItem
,以及执行任务的三种情况:1-我们控件的属性(不可浏览且隐藏)SelectedIndex
,2-我们控件的 MethodFindNextItem
,以及 3-ListView 的 EventItemSelectionChanged
,它触发我们的控件的 Event(ItemSelectionChanged
)(代码片段 #1),当选择新行时必须引发该 Event,并提供一个包含所选行所有 **SubItems** 值的**字符串数组**,还有一个简单的 Sub()(代码片段 #2)用于在检测到无效的负索引时显示错误消息,以及一个 Function(GetSubItems
),它准备上述**字符串数组**,也用于 MethodFindNextItem
。
Public Event ItemSelectionChanged(SubItems As Array)
Private Sub MsgNoNeg(Prefx As String)
MsgBox(Prefx & " cannot be negative...", _
MsgBoxStyle.Critical, _Error)
End Sub
Private Sub ShowSelectedItem()
Dim BoxName As String
For iCtr As Integer = 0 To _ColumnIndex
BoxName = "Box" & iCtr.ToString
Controls(BoxName).Text = MyLV.Items(_SelectedIndex).SubItems(iCtr).Text
Next
End Sub
Private Function GetSubItems() As Array
Dim SubItems(_ColumnIndex) As String
For iSI As Integer = 0 To _ColumnIndex
SubItems(iSI) = MyLV.Items(_SelectedIndex).SubItems(iSI).Text
Next
Return SubItems
End Function
<Browsable(False)> _
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
Public Property SelectedIndex() As Integer
Get
Return _SelectedIndex
End Get
Set(ByVal value As Integer)
If value < 0 Then
MsgNoNeg("Index")
Else
If value >= _ItemsCount Then
MsgBox("Last Index = " & (_ItemsCount - 1).ToString, _
MsgBoxStyle.Critical, _Error)
Else
If _SelectedIndex >= 0 Then
MyLV.Items(_SelectedIndex).Selected = False
End If
_SelectedIndex = value
MyLV.Items(_SelectedIndex).Selected = True
ShowSelectedItem()
ShowHideList(Show:=False) 'Close List
End If
End If
End Set
End Property
Public Function FindNextItem(ColumnIndex As Integer, SearchString As String) As Array
Dim FoundItem(_ColumnIndex) As String
If ColumnIndex >= 0 Then
If ColumnIndex > _ColumnIndex Then
MsgBox("Maximum ColumnIndex is " & _ColumnIndex.ToString & "...", _
MsgBoxStyle.Critical, _Error)
Else
If ColumnIndex = _FNIlastIdx And SearchString = _FNIlastStr Then
' Same values, serch next
_FNI_iFrom += 1
Else
' New values, search first
_FNI_iFrom = 0
_FNIlastIdx = ColumnIndex
_FNIlastStr = SearchString
End If
If _FNI_iFrom >= 0 Then
Dim Found As Boolean = False
Dim iCtr As Integer
For iCtr = _FNI_iFrom To _ItemsCount - 1
If Strings.InStr(MyLV.Items(iCtr).SubItems(ColumnIndex).Text, _
SearchString, CompareMethod.Text) > 0 Then
' Item found...
Found = True
_SelectedIndex = iCtr
FoundItem = GetSubItems()
' Select Item
If _SelectedIndex >= 0 Then
MyLV.Items(_SelectedIndex).Selected = False
End If
MyLV.Items(_SelectedIndex).Selected = True
ShowSelectedItem()
ShowHideList(True)
Exit For
End If
Next
_FNI_iFrom = iCtr
If Found = False And iCtr = _ItemsCount Then
MsgBox("No match...", MsgBoxStyle.Information, "Info")
FoundItem = Nothing
End If
End If
End If
Else
MsgNoNeg("ColumnIndex")
End If
Return FoundItem
End Function
Private Sub MyLV_ItemSelectionChanged(sender As Object, e As ListViewItemSelectionChangedEventArgs) _
Handles MyLV.ItemSelectionChanged
Dim FoundItem(_ColumnIndex) As String
If e.IsSelected Then
_SelectedIndex = e.ItemIndex
ShowSelectedItem()
ShowHideList(False) ' Close List
RaiseEvent ItemSelectionChanged(GetSubItems)
End If
End Sub
- 再有两个简单的 Method,
Clear
和DropDown
。
Public Sub Clear()
MyLV.Items.Clear()
_ItemsCount = 0
For iCtr As Integer = 0 To _ColumnIndex
Controls("Box" & iCtr.ToString).Text = ""
Next
ShowHideList(False) ' Close the List
End Sub
Public Sub DropDown()
ShowHideList(True) ' Drop-down the List
End Sub
就是这样。我将控件的代码组织在 Regions 中。
Imports
Enums & Variables
Public Properties
Public Methods
Public Event
Control Events
Private Subs/Functions
Initialization
#Region "Initialization"
是 Designer 生成的代码。
最后,在你的 WinForms 应用程序中。
- 将 *MCCB.dll* 复制到其 **StartupPath**(项目内的 *\\bin\\Debug* 或 *\\bin\\Release*),然后复制到最终 .EXE 的文件夹。
- 在 Visual Studio 中,添加引用:菜单 *PROJECT - Add Reference... - Browse... - MCCB.dll*
- 在 Toolbox 中放置一个图标(
):菜单 **TOOLS - Choose Toolbox Items... - .NET Framework Components - Browse... - MCCB.dll**。图标将出现在 **All Windows Forms** 组下。
控件自身属性、方法和事件的简要说明。
属性
BoxBackColor
- Box(es) 的背景色。BoxBorderStyle
- Box(es) 的边框样式。BoxForeColor
- Box(es) 的前景色。BoxHeight
- Box(es) 的高度。HeaderBackColor
- Header(s) 的背景色。HeaderBorderStyle
- Header(s) 的边框样式。HeaderForeColor
- Header(s) 的前景色。HeaderHeight
- Header(s) 的高度。LayerOrder
- 控件的图层顺序操作。ListBackColor
- 列表的背景色。ListBorderStyle
- 列表的边框样式。ListFontStyle
- 当控件字体更改为粗体时的列表操作。ListForeColor
- 列表的前景色。MaxItemsDisp
- 列表显示的最大项数。SelectedIndex
- 列表中被(或将要)选中的项的索引。
方法
AddColumn(Width As Integer, Text As String, [Align As HorizontalAlignment = HorizontalAlignment.Left])
- 添加一列,给定其宽度(像素)、其(标题)文本和其对齐方式(左、中、右)。AddRow(SubItems As Array) As Boolean
- 向列表添加一行,给定一个字符串数组。返回一个Boolean
,指示操作的成功(True
)或失败(False
)。Clear
- 清空控件的列表和框。DropDown
- 下拉列表。FindNextItem(ColumnIndex As Integer, SearchString As String) As Array
- 在给定 **Index** 的列值中查找给定 **String** 的下一个出现。匹配发生的行将被选中,并返回其 SubItems 的数组。当没有更多匹配项时,数组为 Nothing,但最后选中的行仍保持选中状态。
事件
ItemSelectionChanged(SubItems As Array)
- 当从列表中选择新行时触发。
历史
2016 年 3 月 9 日 - 首次发布