【问题标题】:Detect when TextBox autocomplete list is showing检测何时显示 TextBox 自动完成列表
【发布时间】:2016-12-01 13:42:32
【问题描述】:

我有 TextBox 控件和关联的计时器,它们在每个 KeyDownMouseClick 事件上重新启动,并在没有这些事件的 3 秒后根据键入的文本执行查询。到目前为止一切顺利。

但我的一些文本框也有用户可以浏览的自动完成列表,但即使他们使用键盘箭头键,计时器也不会停止,并且在用户浏览列表的过程中会触发意外查询。

问题:有没有办法检测自动完成列表何时显示,以便我可以暂停计时器或忽略它的滴答声?

非常感谢!

【问题讨论】:

  • 您可以使用EnumThreadWindows 查找所有自动完成下拉窗口并检查它们是否可见。自动完成下拉窗口类名称为Auto-Suggest Dropdown。您可以使用GetClassName 方法获取枚举窗口的类名,然后使用IsWindowVisible 方法检查窗口是否可见。

标签: .net vb.net winforms autocomplete textbox


【解决方案1】:

您可以使用EnumThreadWindows 查找所有自动完成下拉窗口并检查它们是否可见。自动完成下拉窗口类名称为Auto-Suggest Dropdown。您可以使用GetClassName 方法获取枚举窗口的类名,然后使用IsWindowVisible 方法检查窗口是否可见。

示例

在下面的示例中,我在问题的代码中使用了一个计时器,在计时器的滴答事件中,我检查了是否打开了一个自动完成窗口,我在标题中显示了“打开”表格,否则显示“关闭”:

Delegate Function EnumThreadDelegate(hWnd As IntPtr, lParam As IntPtr) As Boolean

<System.Runtime.InteropServices.DllImport("user32.dll")> _
Shared Function EnumThreadWindows(dwThreadId As Integer, _
    lpfn As EnumThreadDelegate, lParam As IntPtr) As Boolean
End Function

<System.Runtime.InteropServices.DllImport("user32.dll")> _
Shared Function GetClassName(ByVal hWnd As System.IntPtr,
    lpClassName As System.Text.StringBuilder, _
    nMaxCount As Integer) As Integer
End Function

<System.Runtime.InteropServices.DllImport("kernel32.dll")> _
Shared Function GetCurrentThreadId() As Integer
End Function

<System.Runtime.InteropServices.DllImport("user32.dll")> _
Shared Function IsWindowVisible(hWnd As IntPtr) As Boolean
End Function

Const AutoCompleteClassName As String = "Auto-Suggest Dropdown"
Function EnumThreadCallback(hWnd As IntPtr, lParam As IntPtr) As Boolean
    Dim className As New System.Text.StringBuilder("", 256)
    GetClassName(hWnd, className, 256)
    If className.ToString() = AutoCompleteClassName AndAlso IsWindowVisible(hWnd) Then
        AnAutoCOmpleteIsOpen = True
    End If
    Return True
End Function
Dim AnAutoCOmpleteIsOpen As Boolean = False
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    AnAutoCOmpleteIsOpen = False
    EnumThreadWindows(GetCurrentThreadId(), _
        New EnumThreadDelegate(AddressOf Me.EnumThreadCallback), IntPtr.Zero)
    If (AnAutoCOmpleteIsOpen) Then
        Me.Text = "Open"
    Else
        Me.Text = "Close"
    End If
End Sub

【讨论】:

  • @RezaAghaei 偶像 + 1 为您的答案 :)
【解决方案2】:

Reza Aghaei 的方法被翻译成 C#:

public delegate bool EnumThreadDelegate(IntPtr hwnd, IntPtr lParam);

[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
bool isAutoCompleteListOpen = false;
EnumThreadDelegate callback = (IntPtr hwnd, IntPtr lParam) =>
{
    var cn = new StringBuilder("", 256);
    GetClassName(hwnd, cn, 256);
    if (cn.ToString() == "Auto-Suggest Dropdown" && IsWindowVisible(hwnd)) {
        isAutoCompleteListOpen = true;
        return false;
    }
    return true;
};

EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero);
return isAutoCompleteListOpen;

为了获得更好的性能,我们在找到一个打开的列表时在回调中返回false,这会停止枚举。

【讨论】:

    猜你喜欢
    • 2012-03-12
    • 1970-01-01
    • 2011-03-12
    • 2010-10-31
    • 1970-01-01
    • 2012-03-10
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多