none
如何将ComboBox下拉列表视图滚动到某项? RRS feed

  • 问题

  • ComboBox 在DropDown样式下,下拉列表会自动搜索以用户输入字符开头的项,并把它放到列表的最顶端,但它只能搜索项的显示部分。为了搜索项的其它列,我自己写了方法,可以查找到需要的项,但若让 Me.SelectedItem = 找到的项,则文本框会立即显示该项的值,从而为继续输入带来不便。如何才能实现其默认效果,让找到的项位于最顶端,而又不让其值出现在文本框中呢?


    韩立学
    2012年1月8日 4:09

答案

  • 我明白了——你的意思是:使用SelectedItem自动滚屏到选中项,使其成为第一项,然后可以继续输入,参考一下代码,尤其是重要部分:

    Imports System.ComponentModel

    <ToolboxBitmap(GetType(ComboBox), "ComboBox.bmp")> Public Class HComboBox
        Inherits ComboBox

        Private backup As String = Nothing

        Public Sub New()
            MyBase.New()
            Me.SelectedValue = 0
        End Sub
        Protected Overrides Sub OnKeyUp(ByVal e As System.Windows.Forms.KeyEventArgs)
            If Me.Items.Count > 0 Then
                Dim query = From row In Me.Items.Cast(Of String)() Where GetHzPy(rowLike Me.Text.Trim & "*" OrElse row Like Me.Text.Trim & "*"
                If query.Count > 0 Then
                    backup = Me.Text
                    Me.SelectedItem = query.FirstOrDefault
                    Me.Text = backup
                    Me.SelectionStart = Me.Text.Length '注意:从1开始索引!
                Else
                    Beep()
                End If
            End If
            e.Handled = True
        End Sub
       
        Public Shared Function GetHzPy(ByVal cnChar As StringAs String
            Dim hzpy As String = ""s As String
            Dim arrCN As Byte()
            Dim area As Integer
            Dim pos As Integer
            Dim code As Integer
            Dim areacode As Integer() = {4521745253457614631846826470104729747614481194811949062493244989650371506145062250906513875144652218526985269852698529805368954481}
            For i As Integer = 1 To cnChar.Length
                s = Mid(cnChari1)
                arrCN = System.Text.Encoding.[Default].GetBytes(s)
                If arrCN.Length > 1 Then
                    area = CShort(arrCN(0))
                    pos = CShort(arrCN(1))
                    code = (area << 8) + pos
                    For j As Integer = 0 To 25
                        Dim max As Integer = 55290
                        If j <> 25 Then max = areacode(j + 1)
                        If areacode(i) <= code AndAlso code < max Then
                            s = System.Text.Encoding.[Default].GetString(New Byte() {CByte((65 + j))})
                            Exit For
                        End If
                    Next
                End If
                hzpy &= s
            Next
            Return hzpy
        End Function
    End Class


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年1月8日 8:25
    版主

全部回复

  • 你好:)

    1)你说下拉列表在Dropdown样式下会自动搜索输入项,对不起,我这里无法重现你的情况,无法实现自动搜索,请仔细看看你还有没有设置其它属性(比如AutoCompleteSource什么的)。

    2)我没有明白你的意思——只能搜索项的显示部分,请具体配合代码和截图说明。

    3)你自己的方法又是什么?是模糊搜索吗?看你的截图不就已经实现了效果么?

    附加说明:点击我签名部分,直接可以把邮件连同项目发给我,我看看(尽量不要数据库)


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年1月8日 4:56
    版主
  • 谢谢回复!

    主要设置如下:

     With Me.ComboBox
                .DropDownStyle = ComboBoxStyle.DropDown
                .DataSource = Me.BindingSource
                .DisplayMember = "mc"
                .ValueMember = "bh"

     End With

    运行时,点击下拉箭头,显示列表,然后在文本框中输入字符,列表会随着输入,渐进式搜索"mc"开头与文本框中匹配的项,如下(提问中的图也是控件本身的默认执行效果):

    但该控件只能搜索DisplayMember 的内容,若想搜索ValueMember 或其它列的内容,则必须自己写方法(这个在KeyUp事件中很容易实现,问题是搜索到后怎么处理,才能既让它出现在列表的的最顶端,而又不让它出现在文本框中)


    韩立学
    2012年1月8日 6:10
  • 你的意思是不是在文本框中输入内容,针对DisplayName和ValueName一同搜索,然后按照DisplayName显示出来?

    比如:

    那么当输入“1”的时候,应该出现“产品2”(因为它的对应Value是1),同时出现“产品11”(DisplayName中包含1)。是这样吗?


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处



    2012年1月8日 7:02
    版主
  • 你的意思是不是在文本框中输入内容,针对DisplayName和ValueName一同搜索,然后按照DisplayName显示出来?

    比如:

    那么当输入“1”的时候,应该出现“产品2”(因为它的对应Value是1),同时出现“产品11”(DisplayName中包含1)。是这样吗?


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处



    不是这个意思,是搜索到后怎么处理,才能既让它符合条件的第一项出现在列表的的最顶端,而又不让它出现在文本框中(否则,会影响继续输入)。我用的是:Me.SelectedItem = 找到的项,这样处理,该项能够出现在列表的最顶端,但同时,它的值也出现在了文本框中,要避免的后者。
    比如:输入123,这时若第一个符合条件的项是:123001,那么,文本框会变成123001,这给继续查找带来了不便,如果要继续查找1234.....,则不能接着输入,必须删除001 。就是要求,在用户最终找到所要的项之前,文本框中的内容始终是用户输入的内容,而不是项的内容。

    说到底,就是要扩展一下原控件的查找范围(不仅仅局限于DisplayMember),但执行效果不变(即用户每输入一个字符,符合条件的项便出现在列表的最顶端,但文本框始终显示用户输入的字符,直到最终找到需要的项为止)


    韩立学


    2012年1月8日 7:36
  • 我明白了——你的意思是:使用SelectedItem自动滚屏到选中项,使其成为第一项,然后可以继续输入,参考一下代码,尤其是重要部分:

    Imports System.ComponentModel

    <ToolboxBitmap(GetType(ComboBox), "ComboBox.bmp")> Public Class HComboBox
        Inherits ComboBox

        Private backup As String = Nothing

        Public Sub New()
            MyBase.New()
            Me.SelectedValue = 0
        End Sub
        Protected Overrides Sub OnKeyUp(ByVal e As System.Windows.Forms.KeyEventArgs)
            If Me.Items.Count > 0 Then
                Dim query = From row In Me.Items.Cast(Of String)() Where GetHzPy(rowLike Me.Text.Trim & "*" OrElse row Like Me.Text.Trim & "*"
                If query.Count > 0 Then
                    backup = Me.Text
                    Me.SelectedItem = query.FirstOrDefault
                    Me.Text = backup
                    Me.SelectionStart = Me.Text.Length '注意:从1开始索引!
                Else
                    Beep()
                End If
            End If
            e.Handled = True
        End Sub
       
        Public Shared Function GetHzPy(ByVal cnChar As StringAs String
            Dim hzpy As String = ""s As String
            Dim arrCN As Byte()
            Dim area As Integer
            Dim pos As Integer
            Dim code As Integer
            Dim areacode As Integer() = {4521745253457614631846826470104729747614481194811949062493244989650371506145062250906513875144652218526985269852698529805368954481}
            For i As Integer = 1 To cnChar.Length
                s = Mid(cnChari1)
                arrCN = System.Text.Encoding.[Default].GetBytes(s)
                If arrCN.Length > 1 Then
                    area = CShort(arrCN(0))
                    pos = CShort(arrCN(1))
                    code = (area << 8) + pos
                    For j As Integer = 0 To 25
                        Dim max As Integer = 55290
                        If j <> 25 Then max = areacode(j + 1)
                        If areacode(i) <= code AndAlso code < max Then
                            s = System.Text.Encoding.[Default].GetString(New Byte() {CByte((65 + j))})
                            Exit For
                        End If
                    Next
                End If
                hzpy &= s
            Next
            Return hzpy
        End Function
    End Class


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年1月8日 8:25
    版主