动态更改文本框的自动完成列表会导致AccessViolationException,任何建议?

Qqb*_*qbt 9 .net c# vb.net exception access-violation

我的客户希望在应用程序的客户表单中有一个文本框,该表单提供了已启动街道名称的适用结尾.他开始输入一个街道名称,文本框提供了一个街道列表,这些街道以他在文本框中输入的字符序列开头.

我对自己说:没关系,文本框具有AutoCompleteCustomSource属性,即使常见的街道名称列表比启动时预先填充的更长,我可以用查询命中数据库,填充AutoCompleteStringCollection并显示对用户而言.

现在就是这样的事情:如果我在每个按键/键盘上填充列表,程序崩溃并抛出AccessViolationException.

我发现那是因为:控件正在显示自动完成列表的同时被修改,导致崩溃.

刷新自动完成列表时,将使用新指针重新创建控件.键盘和鼠标事件(KeyPress,MouseOver,MouseLeave,MouseHover)尝试引用旧控件的指针,这些指针现在在内存中无效,从而导致发生内存访问冲突.

基础AutoComplete实现不允许在窗口上设置AutoComplete候选列表对象后更改它.为了允许更改列表,WinForms会破坏Edit控件或ComboBox并重新创建它.如果在自动完成窗口仍在使用它时销毁基础控件,则会导致异常.

我在MSDN上看到了这个,他们的决议:

不要在关键事件期间动态修改自动完成候选列表.

我也尝试过这个帖子

那么,如果我坚持提供按键按键的适用街道名称,我怎么能做到这一点呢?

注意:我知道你可以通过创建一个自定义控件来实现这一点,但是它可以用纯粹的编码魔法来完成吗?

com*_*ech 4

我们在应用程序中解决这个问题的方法(我们需要从可能的 100,000 个项目中进行选择)是放弃自动完成功能并使用组合框。

我们使用 Infragistics 组合框,但我怀疑标准 Windows 组合框也可以工作。

这里的技巧是在下拉模式下使用组合框本身作为自动完成列表并在用户键入时填充它。

这是我们使用的逻辑:

Private m_fOkToUpdateAutoComplete As Boolean
Private m_sLastSearchedFor As String = ""

Private Sub cboName_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles m_cboName.KeyDown
    Try
        ' Catch up and down arrows, and don't change text box if these keys are pressed.
        If e.KeyCode = Keys.Up OrElse e.KeyCode = Keys.Down Then
            m_fOkToUpdateAutoComplete = False
        Else
            m_fOkToUpdateAutoComplete = True
        End If
    Catch theException As Exception
        ' Do something with the exception
    End Try
End Sub


Private Sub cboName_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_cboName.TextChanged
    Try
        If m_fOkToUpdateAutoComplete Then
            With m_cboName
                If .Text.Length >= 4 Then
                    ' Only do a search when the first 4 characters have changed
                    If Not .Text.Substring(0, 4).Equals(m_sLastSearchedFor, StringComparison.InvariantCultureIgnoreCase) Then
                        Dim cSuggestions As StringCollection
                        Dim sError As String = ""

                        ' Record the last 4 characters we searched for
                        m_sLastSearchedFor = .Text.Substring(0, 4)

                        ' And search for those
                        ' Retrieve the suggestions from the database using like statements
                        cSuggestions = GetSuggestions(m_sLastSearchedFor, sError)
                        If cSuggestions IsNot Nothing Then
                            m_cboName.DataSource = cSuggestions
                            ' Let the list catch up. May need to do Thread.Idle here too
                            Application.DoEvents()
                        End If
                    End If
                Else
                    If Not String.IsNullOrEmpty(m_sLastSearchedFor) Then
                        ' Clear the last searched for text
                        m_sLastSearchedFor = ""
                        m_cboName.DataSource = Nothing
                    End If
                End If
            End With
        End If
    Catch theException As Exception
        ' Do something with the exception
    End Try
End Sub
Run Code Online (Sandbox Code Playgroud)

由于项目数量较多,我们直到用户输入 4 个字符后才开始搜索,但这只是我们的实现。