65.9K
CodeProject 正在变化。 阅读更多。
Home

灵活列表控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (60投票s)

2012 年 2 月 22 日

CPOL

7分钟阅读

viewsIcon

150749

downloadIcon

8402

构建一个允许添加任何内容的列表控件。

333864/screenshot_new.png

引言

在普通的列表框或列表视图控件中,您会受到很多限制。您无法正确添加图像或图标,无法提供自己的高亮颜色或文本放置,还有一个最想要的功能是无法在默认列表控件中添加多行文本。

今天我将向您展示如何构建一个列表控件,该控件可以按照您想要的方式显示列表项。它们可以是多行文本,包含图像,不同大小的文本或背景颜色,复杂的项目放置等。一切都取决于您如何设计。完全灵活!

构建列表控件

我们将使用默认提供的控件来实现这个梦想。我将向您展示如何创建一个列表控件,而如何使用该列表控件则完全取决于您的想象力。因此,我们将创建一个仅包含 FlowLayoutPanel 控件的列表控件。

在您的 Visual Studio 中创建一个新项目。向您的项目添加一个 Usercontrol 并将其命名为 ListControl

在 ListControl 上放置一个 FlowLayoutPanel 并将其命名为 flpListBox

flpListBox 提供以下属性

  • AutoScroll = True
  • AutoSize = False
  • Dock = Fill
  • FlowDirection = TopDown
  • Margin = 0, 0, 0, 0
  • WrapContents = False

并为 ListControl 用户控件提供以下属性

  • BorderStyle = FixedSingle
  • Padding = 0, 0, 0, 0

现在我们需要向 ListControl 添加代码来处理添加、删除、计数和清除功能,就像任何其他列表控件一样。因此,我们将添加四个函数:Add, Remove, Clear,Count

    Public Sub Add(c As Control)

    End Sub

    Public Sub Remove(name As String)

    End Sub

    Public Sub Clear()

    End Sub

    Public ReadOnly Property Count() As Integer
        Get
            Return flpListBox.Controls.Count
        End Get
    End Property 

让我们添加 Add 子程序的代码。如您在定义中所见,Add 子程序接受一个控件作为 listitem,而不是文本或任何其他类型的对象。这是因为我们将创建一个灵活的列表控件,任何类型的独立控件都可以添加到其中,而我们的 ListControl 将像任何其他列表控件一样移动它。

    Public Sub Add(c As Control)
        flpListBox.Controls.Add(c)
    End Sub 

这是简单的代码。它只将您的控件(即列表项)添加到流式布局面板。流式布局面板被设置为以“从上到下”的方式添加所有控件。所有控件都将垂直添加。您不断添加控件,它将不断追加到添加到流式布局面板的控件列表中。现在让我们为 Remove 和 Clear 子程序编写代码。

    Public Sub Remove(name As String)
        Dim c As Control = flpListBox.Controls(Name)
        flpListBox.Controls.Remove(c)
        c.Dispose()
    End Sub
    Public Sub Clear()
        Do
            If flpListBox.Controls.Count = 0 Then Exit Do
            Dim c As Control = flpListBox.Controls(0)
            flpListBox.Controls.Remove(c)
            c.Dispose()
        Loop
    End Sub 

我首先要在这里讨论 Clear 子程序。为了从您的列表控件中删除所有控件,有一种非常简单的方法。只需调用 flpListBox.Controls.Clear,它就会删除所有控件。但这些控件仍然保留在内存中。这取决于您的编码方法或您的编程需求,但我更喜欢我的列表控件在从列表控件中删除控件后立即将其处置掉。为了做到这一点,我们首先需要从流式布局面板中获取控件,将其从其控件列表中移除,然后最后将其处置掉。

Clear 子程序中,上述处置过程会重复进行,直到列表中的所有控件都已删除。但在 Remove 子程序中,当然我们只需要对用户请求移除的控件执行一次此过程。

使用控件

我们的 ListControl 已完成。您可以在此阶段试运行此控件。将 ListControl 放置在一个新窗体上,并将以下代码添加到 Load 事件中。

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        For i as Integer = 1 To 20
            Dim btn As New Button
            With btn
                .Name = "b" & i
                .Text = "Button " & i
                .Height = 25
                .Margin = New Padding(0)
            End With
            ListControl1.Add(btn)
        Next
    End Sub 

上面的代码将向 ListControl 添加二十个按钮。对于这些按钮中的每一个,您都可以通过在您窗体的代码中使用 AddHandler 来挂接一个点击事件。

333864/scr1.png

我将按钮的 Margin 属性设置为零的原因是为了减小我们列表控件中每一行之间的行间距。

我们的 ListControl 已准备就绪。当项目超过列表控件的高度时,它将自动显示滚动条。您还可以使用鼠标滚轮滚动。目前它不处理大小调整事件,如果您可能想要调整控件的大小以适应 ListControl 的宽度。

管理大小和大小调整事件

到此,我们的列表控件已完成。您可能希望在其中添加不规则大小的控件,这完全取决于您。您甚至可以制作出一些漂亮的东西,如下所示

333864/scr2.png

因为它是流式布局面板控件,所以它允许您添加任何内容,它将自行管理其放置。但仅限于放置,不包括大小。大小由您定义。

为了构建一个外观良好的列表控件,我们还需要在此处自动化大小。为此,需要添加以下代码

    Private Sub SetupAnchors()
        If flpListBox.Controls.Count > 0 Then
            For i = 0 To flpListBox.Controls.Count - 1
                Dim c As Control = flpListBox.Controls(i)
                If i = 0 Then
                    ' Its the first control, all subsequent controls follow 
                    ' the anchor behavior of this control.
                    c.Anchor = AnchorStyles.Left + AnchorStyles.Top
                    c.Width = flpListBox.Width - SystemInformation.VerticalScrollBarWidth
                Else
                    ' It is not the first control. Set its anchor to
                    ' copy the width of the first control in the list.
                    c.Anchor = AnchorStyles.Left + AnchorStyles.Right
                End If
            Next
        End If
    End Sub
    
    Private Sub flpListBox_Layout(sender As Object, e As System.Windows.Forms.LayoutEventArgs) Handles flpListBox.Layout
        If flpListBox.Controls.Count Then
            flpListBox.Controls(0).Width = flpListBox.Size.Width - SystemInformation.VerticalScrollBarWidth
        End If
    End Sub 

我们添加了一个名为 SetupAnchors 的子例程。在流式布局面板中,如果将控件的锚点设置为左+右,则其中的所有控件都可以拥有自己的高度,但对于宽度,它们都采用列表中第一个控件的宽度。第一个控件的宽度是多少,其他控件就会自动跟随。但是第一个控件不能有左+右锚点。您必须手动定义第一个控件的宽度。流式布局面板默认就是这样工作的。

因此,在上面,我已经为列表中的第一个控件设置了顶部+左锚点,而所有其他控件都具有左+右锚点。结果,所有控件都将跟随第一个控件的宽度。因此,每当 ListControl 被调整大小时,它只会调整第一个控件的大小(请参阅 flpListBox.Resize 事件),而其他控件将自动复制其宽度。

相应地修改 AddRemove 子程序,以便在控件添加到列表或从列表中删除时调用 SetupAnchors 子程序。

    Public Sub Add(c As Control)
        flpListBox.Controls.Add(c)
        SetupAnchors()
    End Sub
    Public Sub Remove(name As String)
        Dim c As Control = flpListBox.Controls(Name)
        flpListBox.Controls.Remove(c)
        c.Dispose()
        SetupAnchors()
    End Sub 

将其提升到更高层次

由于 ListControl 允许添加任何类型的控件,并且它会像其他列表控件项一样处理它,因此您甚至可以制作自定义用户控件并将其添加到 ListControl 中。在页面顶部的第一个截图中,我创建了一个自定义用户控件,它管理自己的高亮和颜色、文本放置、图标和星级等。 ListControl 所做的就是将其添加到其列表中。

为了实现这一点,让我们对上面解释的代码做一些改进。我做了一些小小的改动……现在您不必创建一个新控件添加到列表中,ListControl 会为您完成。这完全取决于您的需求!您可以根据您的应用程序需求旋转、扭曲、翻转此控件。您可以将所有内容嵌入 ListControl 中,也可以手动创建一个新控件并附加它。

我构建了一个名为 ListControlItem 的列表项控件,它具有以下属性:歌曲名称、艺术家名称、专辑名称、歌曲时长、歌曲或专辑的图像、歌曲的评分。

注意:由于本文档仅用于演示 ListControl 的可能性,因此我不会解释 ListControlItem 的代码。要查看 ListControlItem 的代码,请下载示例项目并查看。

所以我更改了 Add 过程如下

    Public Sub Add(Song As String, Artist As String, Album As String, Duration As String, SongImage As Image, Rating As Integer)
        Dim c As New ListControlItem
        With c
            ' Assign an auto generated name
            .Name = "item" & flpListBox.Controls.Count + 1
            .Margin = New Padding(0)
            ' set properties
            .Song = Song
            .Artist = Artist
            .Album = Album
            .Duration = Duration
            .Image = SongImage
            .Rating = Rating
        End With
        ' To check when the selection is changed
        AddHandler c.SelectionChanged, AddressOf SelectionChanged
        '
        flpListBox.Controls.Add(c)
        SetupAnchors()
    End Sub 

并且 Remove 过程已被修改为

    Public Sub Remove(name As String)
        ' grab which control is being removed
        Dim c As ListControlItem = flpListBox.Controls(name)
        flpListBox.Controls.Remove(c)
        ' remove the event hook
        RemoveHandler c.SelectionChanged, AddressOf SelectionChanged
        ' now dispose off properly
        c.Dispose()
        SetupAnchors()
    End Sub 

由于我为 ListControlItem 添加了一个事件挂钩来监控选择何时更改,因此在处置控件时,删除挂钩也是一种高效的编程实践。

并且我添加了另一个子程序来确保一次只有一个列表项被选中

    Dim mLastSelected As ListControlItem = Nothing
    Private Sub SelectionChanged(sender As Object)
        If mLastSelected IsNot Nothing Then
            mLastSelected.Selected = False
        End If
        mLastSelected = sender
    End Sub 

就是这样!

现在,在使用修改后的 ListControl 时,您无需创建或处置控件。所有这些都将由其自行处理。您可以这样从您的 Windows Form 中将项添加到列表中

ListControl1.Add("Party Rock Anthem (feat. Lauren Bennett & GoonRock)", "LMFAO", "For DJs Only [2011]", "4:23", ImageList1.Images(7), 5) 

查看示例代码

我们的 ListControl 终于完成了。它可能不像默认的 listview 或 listbox 控件或任何其他第三方 listview 控件那样内存效率高,但它工作得非常好,并提供了其他列表控件所不具备的灵活性。

这个小小的示例项目旨在演示 ListControl 如何用于媒体播放器类型的应用程序。它取决于您正在构建的应用程序类型。列表项的外观完全取决于您,因为您将设计列表项,ListControl 只会在列表中进行管理。

© . All rights reserved.