【问题标题】:Is there a way to keep the index order of a listbox after sorting items?有没有办法在排序项目后保持列表框的索引顺序?
【发布时间】:2021-05-16 15:19:11
【问题描述】:

对于我的课程作业,我正在使用 Visual Basic 制作一个预订系统,该系统还存储有关未付款项的数据,我使用列表框显示保存在数组中的注册客户的姓名,使用列表框项的索引结合数组的主键,例如:

数组:

User ID Amount Owed
0 100
1 0
2 200

然后将其添加到列表框中,姓名和联系信息等客户数据存储在发票数据的单独数组中,通过用户 ID 作为主键链接。

列表框:

Index Name
0 John Doe
1 Jane Doe
2 Joe Bloggs

这个系统一切正常,直到我想添加一个复选框来过滤掉没有未付款项的人 过滤列表框:

Index Name User ID
0 John Doe 0
1 Joe Bloggs 2

如您所见,列表框的索引现在不再与用户 ID 相同,这反过来又破坏了我涉及使用 .SelectedIndex 函数的其他操作。

这是这个过程涉及的代码

Private Sub SortOpenInvoice_CheckedChanged(sender as Object, e as EventArgs) _
    Handles CheckBox1.CheckedChanged

    Dim HasOpenInvoice As Boolean

    HasOpenInvoice = False
    If SortOpenInvoice.Checked = True Then
        For i = 0 To numofCustomers - 1
            For j = 0 To numofInvoices - 1
                If invoices(j).AmountOwed > 0 And invoices(j).CustomerID = customers(i).CustomerID Then 'Searches for an open invoice (outstanding payment) linked to a customers ID
                    HasOpenInvoice = True  'Flag for if there is an open invoice (outstanding payment)
                End If
            Next
            If HasOpenInvoice = False Then
                lbxMemberList.Items.RemoveAt(Convert.ToInt32(customers(i).CustomerID)) 'Removes index if no open invoice is found
            Else
                HasOpenInvoice = False
            End If
        Next
    ...
End Sub

在过滤掉特定字段后,我可以做些什么来保留索引值?或者您有没有其他可以建议的替代解决方案?

谢谢!

【问题讨论】:

    标签: vb.net listbox


    【解决方案1】:

    我建议使用另一种方法。

    将 ListBox 的 Sorted 属性设置为 True,并将客户列表分配给 ListBox 的 DataSource 属性。

    现在,在 ListBox 中,客户显示为已排序,但在列表中保持未排序。我还建议将列表包含在BindingList 中。它的优点是可以在您添加或删除客户时自动更新 ListBox。

    您还必须重写 Customer 类的 ToString 方法才能让 ListBox 以适当的方式显示它们:

    Class Customer
        Public Property UserID As Integer
        Public Property AmountOwed As Decimal
        Public Property Name As String
    
        Public Overrides Function ToString() As String
            Return $"{Name} {UserID}, $={AmountOwed:n2}"
        End Function
    End Class
    

    形式(例如):

    Private customerBindingList As BindingList(Of Customer)
    
    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
    
        ' Set up example list of customers
        Dim customers = New List(Of Customer) From {
            New Customer With {.UserID = 0, .Name = "John Doe", .AmountOwed = 100},
            New Customer With {.UserID = 1, .Name = "Jane Doe", .AmountOwed = 0},
            New Customer With {.UserID = 2, .Name = "Joe Bloggs", .AmountOwed = 200}
        }
    
        ' Use the customers as data source of the ListBox via a BindingList.
        customerBindingList = New BindingList(Of Customer)(customers)
        ListBox1.DataSource = customerBindingList
    End Sub
    

    我们的想法是使用customerBindingList,而不是使用ListBox。从 ListBox 中,您可以通过 SelectedItem 属性获取选定的客户。这比使用索引要健壮得多。无论如何,您都无法使 UserID 与任何索引保持同步。 UserID 必须保持不变,这样您才能可靠地识别客户,而索引会在添加或删除(或排序)客户时发生变化。

    不使用索引的删除函数示例:

    Private Sub DeleteButton_Click(sender As Object, e As EventArgs) Handles DeleteButton.Click
        Dim customer = DirectCast(ListBox1.SelectedItem, Customer)
    
        customerBindingList.Remove(customer)
    End Sub
    

    您还可以将 ListBox 的 DisplayMember 属性设置为“名称”,而不是覆盖 ToString

    您可以将 ListBox 的ValueMember 属性设置为“UserID”。这使您可以使用

    访问用户ID
    Dim id As Integer = DirectCast(ListBox1.SelectedValue, Integer)
    

    【讨论】:

      最近更新 更多