有没有办法在排序项目后保持列表框的索引顺序?
Is there a way to keep the index order of a listbox after sorting items?
对于我的课程作业,我在 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
过滤掉特定字段后,如何保留索引值?或者您是否可以建议任何其他替代解决方案?
谢谢!
我建议使用另一种方法。
将ListBox的Sorted
属性设置为True
并将客户列表分配给ListBox的DataSource
属性。
现在,在 ListBox 中,客户显示为已排序,但他们在列表中仍未排序。我还建议将列表包装在 BindingList
中。它的优点是在您添加或删除客户时自动更新列表框。
您还必须重写客户 class 的 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)
对于我的课程作业,我在 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
过滤掉特定字段后,如何保留索引值?或者您是否可以建议任何其他替代解决方案?
谢谢!
我建议使用另一种方法。
将ListBox的Sorted
属性设置为True
并将客户列表分配给ListBox的DataSource
属性。
现在,在 ListBox 中,客户显示为已排序,但他们在列表中仍未排序。我还建议将列表包装在 BindingList
中。它的优点是在您添加或删除客户时自动更新列表框。
您还必须重写客户 class 的 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”。这使您可以使用
Dim id As Integer = DirectCast(ListBox1.SelectedValue, Integer)