从绑定的数据源中对组合框项目进行排序

问题描述 投票:0回答:1

我一直在一遍又一遍地尝试让我的

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 等)。

只是我为了寻求灵感而查看的一些问题的例子:

我觉得我可能忽略了一些非常简单/愚蠢的事情,但我一遍又一遍地重复这个问题,但没有任何进展,也不明白为什么。我在这里做错了什么?

刚刚想到的另一件事可能与此有关:这些

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
vb.net winforms sorting combobox bindingsource
1个回答
0
投票

感谢@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
,一切似乎都按预期运行。

© www.soinside.com 2019 - 2024. All rights reserved.