我一直在一遍又一遍地尝试让我的
ComboBox
项目正确排序,但我所做的似乎都不起作用。我已经查看了许多 SO 主题,并提供了使其发挥作用的各种建议,但无论我尝试什么,每次加载表单时,我的 ComboBox
中的项目都不会被排序。这是我用来填充 ComboBox
: 的基本代码
'ClaimCodes is a class-level variable
Private ClaimCodes As DataTable
Private Sub LoadCodeComboBoxes()
Dim CodeTable As DataTable
Dim DescriptionTable As DataTable
Dim DescriptionBinding As New BindingSource
Dim CodeBinding As New BindingSource
Using MyDB As New DbConnection("my connection string")
ClaimCodes = MyDB.ExecuteStatement("SELECT code, descr FROM code_table WHERE code > 0")
End Using
CodeTable = ClaimCodes.Copy
CodeTable.DefaultView.Sort = "code ASC"
CodeTable = CodeTable.DefaultView.ToTable
DescriptionTable = ClaimCodes.Copy
DescriptionTable.DefaultView.Sort = "descr ASC"
DescriptionTable = DescriptionTable.DefaultView.ToTable
CodeBinding.DataSource = CodeTable
CodeBinding.Sort = "code"
DescriptionBinding.DataSource = DescriptionTable
DescriptionBinding.Sort = "descr"
With Me.cboClaimCode
.DataSource = Nothing
.Items.Clear()
.DataSource = CodeBinding
.ValueMember = "code"
.DisplayMember = "code"
.AutoCompleteSource = AutoCompleteSource.ListItems
.AutoCompleteMode = AutoCompleteMode.SuggestAppend
.SelectedIndex = -1
End With
With Me.cboClaimCodeDescription
.DataSource = Nothing
.Items.Clear()
.DataSource = DescriptionBinding
.ValueMember = "code"
.DisplayMember = "descr"
.AutoCompleteSource = AutoCompleteSource.ListItems
.AutoCompleteMode = AutoCompleteMode.SuggestAppend
.SelectedIndex = -1
End With
End Sub
我尝试了上述的各种迭代,包括:
BindingSource
物体并直接使用XXXTable.DefaultView
Sort
应用于 DataTable
级别、BindingSource
级别以及两者SelectedIndex
的 ComboBox
属性以显示项目,而不是将其设置为 -1
(未选择)ComboBox
属性设置的顺序,以便 DataSource
设置在 ValueMember
和 DisplayMember
.Sorted
的 ComboBox
属性设置为 true (当然,这会引发异常,因为该对象绑定到 DataSource
)ClaimCodes
DataTable
(应用任何排序之前)有 17 行:
+---------------------+
| code | descr |
+---------------------+
| 10 | <code desc> |
| 11 | <code desc> |
| 13 | <code desc> |
| 14 | <code desc> |
| 15 | <code desc> |
| 30 | <code desc> |
| 35 | <code desc> |
| 99 | <code desc> |
| 1 | <code desc> |
| 36 | <code desc> |
| 54 | <code desc> |
| 60 | <code desc> |
| 29 | <code desc> |
| 61 | <code desc> |
| 50 | <code desc> |
| 71 | <code desc> |
| 70 | <code desc> |
+---------------------+
应用排序后,我可以检查对象(
DataTable
和/或BindingSource
)并在Watch窗口中查看结果。从那里,它们按预期排序(1、10、11 等)。但是,当显示表单时,ComboBox
中的项目未排序,并以与原始未排序的DataTable
相同的顺序显示(10、11、13 等)。
只是我为了寻求灵感而查看的一些问题的例子:
DataTable
中作为System.Int32
)我觉得我可能忽略了一些非常简单/愚蠢的事情,但我一遍又一遍地重复这个问题,但没有任何进展,也不明白为什么。我在这里做错了什么?
我刚刚想到的另一件事可能与此有关:这些
ComboBox
具有以下属性:
OwnerDrawFixed
DropDownList
System
True
不确定
OwnerDrawFixed
是否可能与此有关,但我使用它来实现自定义 .DrawItem
事件处理程序,以在选择 ComboBox
时突出显示它。
我将其中一个
DrawMode
上的 ComboBox
切换回 Normal
并再次尝试,但这些项目仍然“未排序”。看来这不是问题的原因。
如前所述,我使用自定义
DrawItem
处理程序来处理 ComboBox
,以便在选择它时进行视觉样式设置。这是该事件处理程序的代码,基本上在每个 ComboBox
es 上重用:
Private Sub cboClaimCode_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles cboClaimCode.DrawItem
Dim ComboBox As ComboBox = TryCast(sender, ComboBox)
Dim ComboBoxFont As Font = ComboBox.Font
Dim ComboBoxColor As Color
Dim TextColor As Color
Dim ComboBoxBounds As Rectangle = e.Bounds
Dim TextBrush As SolidBrush
Dim ComboBoxBrush As SolidBrush
If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
TextColor = SystemColors.WindowText
ComboBoxColor = Colors.PaleBlue
Else
TextColor = SystemColors.WindowText
ComboBoxColor = SystemColors.Window
End If
TextBrush = New SolidBrush(TextColor)
ComboBoxBrush = New SolidBrush(ComboBoxColor)
e.Graphics.FillRectangle(ComboBoxBrush, ComboBoxBounds)
If e.Index >= 0 Then
If Not IsCellEmpty(ClaimCodes(e.Index)("code")) Then
e.Graphics.DrawString(ClaimCodes(e.Index)("code").ToString, ComboBoxFont, TextBrush, New RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height))
End If
End If
End Sub
感谢@LarsTech 和@Jimi 的评论,帮助我找到问题所在。当我测试时,我还注意到这些选择也没有完全按照预期工作(我之前没有注意到这一点),因此他们的评论完全向我指出了不同的方向。
正如问题中提到的,我有一个针对这些
DrawItem
的自定义 ComboBox
事件处理程序。该事件处理程序引用“原始”、未排序的DataTable
来添加一些用户体验“美化”,以便用户能够更轻松地识别何时选择了ComboBox
(如果没有它,用户将很难看到何时盒子处于焦点)。
为了解决这个问题,我将
DataTable
使用的 ComboBox
移至类级别,而不是在方法中:
Public Class MyForm
Private ClaimCodes As DataTable
Private ClaimCodeDescriptions As DataTable
[...]
End Class
(是的,我重复使用了之前的
ClaimCodes
对象名称)
然后我更改了
LoadCodeComboBoxes()
方法来填充那些类级别 DataTable
对象而不是方法本地对象:
Private Sub LoadCodeComboBoxes()
Dim CodeTable As DataTable
Dim DescriptionBinding As New BindingSource
Dim CodeBinding As New BindingSource
Using MyDB As New DbConnection("my connection string")
CodeTable = MyDB.ExecuteStatement("SELECT code, descr FROM code_table WHERE code > 0")
End Using
ClaimCodes = CodeTable.Copy
ClaimCodes.DefaultView.Sort = "code ASC"
ClaimCodes = ClaimCodes.DefaultView.ToTable
ClaimCodeDescriptions = CodeTable.Copy
ClaimCodeDescriptions.DefaultView.Sort = "descr ASC"
ClaimCodeDescriptions = ClaimCodeDescriptions.DefaultView.ToTable
CodeBinding.DataSource = ClaimCodes
CodeBinding.Sort = "code"
DescriptionBinding.DataSource = ClaimCodeDescriptions
DescriptionBinding.Sort = "descr"
With Me.cboClaimCode
.DataSource = Nothing
.DisplayMember = "code"
.ValueMember = "code"
.DataSource = CodeBinding
.AutoCompleteSource = AutoCompleteSource.ListItems
.AutoCompleteMode = AutoCompleteMode.SuggestAppend
.SelectedIndex = -1
End With
With Me.cboClaimCodeDescription
.DataSource = Nothing
.DisplayMember = "descr"
.ValueMember = "code"
.DataSource = DescriptionBinding
.AutoCompleteSource = AutoCompleteSource.ListItems
.AutoCompleteMode = AutoCompleteMode.SuggestAppend
.SelectedIndex = -1
End With
End Sub
最后,我更新了我的
DrawItem
事件处理程序以使用单独的类级别 DataTable
:
Private Sub cboClaimCodeDescription_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles cboClaimCodeDescription.DrawItem
Dim ComboBox As ComboBox = TryCast(sender, ComboBox)
Dim ComboBoxFont As Font = ComboBox.Font
Dim ComboBoxColor As Color
Dim TextColor As Color
Dim ComboBoxBounds As Rectangle = e.Bounds
Dim TextBrush As SolidBrush
Dim ComboBoxBrush As SolidBrush
If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
TextColor = SystemColors.WindowText
ComboBoxColor = Colors.Blue
Else
TextColor = SystemColors.WindowText
ComboBoxColor = SystemColors.Window
End If
TextBrush = New SolidBrush(TextColor)
ComboBoxBrush = New SolidBrush(ComboBoxColor)
e.Graphics.FillRectangle(ComboBoxBrush, ComboBoxBounds)
If e.Index >= 0 Then
If Not IsCellEmpty(ClaimCodeDescriptions(e.Index)("descr")) Then
e.Graphics.DrawString(ClaimCodeDescriptions(e.Index)("descr").ToString, ComboBoxFont, TextBrush, New RectangleF(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height))
End If
End If
End Sub
现在每个人都使用自己的、已排序的
DataTable
,一切似乎都按预期运行。