Imports System.ComponentModel Imports System.Runtime.InteropServices Imports System.Text Public Class TextBoxEx Inherits TextBox Private acDropDownHeight As Integer = 106 Private acDropDownWidth As Integer = 170 ‘<EditorBrowsable(EditorBrowsableState.Always), _ <Browsable(True), Description("The width, in pixels, of the auto complete drop down box"), DefaultValue(170)> _ Public Property AutoCompleteDropDownWidth() As Integer Get Return acDropDownWidth End Get Set(value As Integer) acDropDownWidth = value End Set End Property ‘<EditorBrowsable(EditorBrowsableState.Always), _ <Browsable(True), Description("The height, in pixels, of the auto complete drop down box"), DefaultValue(106)> _ Public Property AutoCompleteDropDownHeight() As Integer Get Return acDropDownHeight End Get Set(value As Integer) acDropDownHeight = value End Set End Property Protected Overrides Sub OnHandleCreated(e As EventArgs) MyBase.OnHandleCreated(e) ACWindow.RegisterOwner(Me) End Sub ‘‘‘ <summary> ‘‘‘ Provides an encapsulation of an Auto complete drop down window ‘‘‘ handle and window proc. ‘‘‘ </summary> Private Class ACWindow Inherits NativeWindow Private Shared ReadOnly ACWindows As Dictionary(Of IntPtr, ACWindow) Private Const WM_WINDOWPOSCHANGED As UInt32 = &H47 Private Const WM_NCDESTROY As UInt32 = &H82 Private Const SWP_NOSIZE As UInt32 = &H1 Private Const SWP_NOMOVE As UInt32 = &H2 Private Const SWP_NOZORDER As UInt32 = &H4 Private Const SWP_NOREDRAW As UInt32 = &H8 Private Const SWP_NOACTIVATE As UInt32 = &H10 Private Const WM_SIZING As UInt32 = &H214 Private Const GA_ROOT As UInt32 = 2 Private Shared ReadOnly owners As List(Of TextBoxEx) <DllImport("user32.dll")> _ Private Shared Function EnumThreadWindows(dwThreadId As Integer, lpfn As EnumThreadDelegate, lParam As IntPtr) As Boolean End Function <DllImport("user32.dll")> _ Private Shared Function GetAncestor(hWnd As IntPtr, gaFlags As UInt32) As IntPtr End Function <DllImport("kernel32.dll")> _ Private Shared Function GetCurrentThreadId() As Integer End Function <DllImport("user32.dll")> _ Private Shared Sub GetClassName(hWnd As IntPtr, lpClassName As StringBuilder, nMaxCount As Integer) End Sub <DllImport("user32.dll")> _ Private Shared Function SetWindowPos(hWnd As IntPtr, hWndInsertAfter As IntPtr, X As Integer, Y As Integer, cx As Integer, cy As Integer, _ uFlags As UInteger) As Boolean End Function <DllImport("user32.dll")> _ Private Shared Function GetWindowRect(hWnd As IntPtr, ByRef lpRect As RECT) As Boolean End Function Private Delegate Function EnumThreadDelegate(hWnd As IntPtr, lParam As IntPtr) As Boolean <StructLayout(LayoutKind.Sequential)> _ Private Structure RECT Public ReadOnly Left As Integer Public ReadOnly Top As Integer Public ReadOnly Right As Integer Public ReadOnly Bottom As Integer Public ReadOnly Property Location() As Point Get Return New Point(Left, Top) End Get End Property End Structure Private owner As TextBoxEx Shared Sub New() ACWindows = New Dictionary(Of IntPtr, ACWindow)() owners = New List(Of TextBoxEx)() End Sub ‘‘‘ <summary> ‘‘‘ Creates a new ACWindow instance from a specific window handle. ‘‘‘ </summary> Private Sub New(handle As IntPtr) AssignHandle(handle) End Sub ‘‘‘ <summary> ‘‘‘ Registers a ComboBoxEx for adjusting the Complete Dropdown window size. ‘‘‘ </summary> Public Shared Sub RegisterOwner(owner As TextBoxEx) If (owners.Contains(owner)) Then Return End If owners.Add(owner) EnumThreadWindows(GetCurrentThreadId(), AddressOf EnumThreadWindowCallback, IntPtr.Zero) End Sub ‘‘‘ <summary> ‘‘‘ This callback will receive the handle for each window that is ‘‘‘ associated with the current thread. Here we match the drop down window name ‘‘‘ to the drop down window name and assign the top window to the collection ‘‘‘ of auto complete windows. ‘‘‘ </summary> Private Shared Function EnumThreadWindowCallback(hWnd As IntPtr, lParam As IntPtr) As Boolean If (GetClassName(hWnd) = "Auto-Suggest Dropdown") Then Dim handle As IntPtr = GetAncestor(hWnd, GA_ROOT) If (Not ACWindows.ContainsKey(handle)) Then ACWindows.Add(handle, New ACWindow(handle)) End If End If Return True End Function ‘‘‘ <summary> ‘‘‘ Gets the class name for a specific window handle. ‘‘‘ </summary> Private Shared Function GetClassName(hRef As IntPtr) As String Dim lpClassName = New StringBuilder(256) GetClassName(hRef, lpClassName, 256) Return lpClassName.ToString() End Function ‘‘‘ <summary> ‘‘‘ Overrides the NativeWindow‘s WndProc to handle when the window ‘‘‘ attributes changes. ‘‘‘ </summary> Protected Overrides Sub WndProc(ByRef m As Message) ‘If m.Msg = WM_SIZING Then ‘ If owner IsNot Nothing Then ‘ Dim rr As RECT = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(RECT)), RECT) ‘ owner.acDropDownWidth = (rr.Right - rr.Left) ‘ owner.acDropDownHeight = (rr.Bottom - rr.Top) ‘ End If ‘End If Console.WriteLine(m.Msg.ToString()) If (m.Msg = WM_WINDOWPOSCHANGED) Then ‘ If the owner has not been set we need to find the ComboBoxEx that ‘ is associated with this dropdown window. We do it by checking if ‘ the upper-left location of the drop-down window is within the ‘ ComboxEx client rectangle. If (owner Is Nothing) Then Dim ownerRect As Rectangle = Nothing Dim acRect = New RECT() For Each cbo As TextBoxEx In owners GetWindowRect(Handle, acRect) ownerRect = cbo.RectangleToScreen(cbo.ClientRectangle) ‘If (ownerRect.Contains(acRect.Location)) Then owner = cbo ‘ TODO: might not be correct. Was : Exit For ‘Exit For ‘ End If Next owners.Remove(owner) End If If ((owner IsNot Nothing)) Then SetWindowPos(Handle, IntPtr.Zero, -5, 0, owner.AutoCompleteDropDownWidth, owner.AutoCompleteDropDownHeight, _ SWP_NOMOVE Or SWP_NOZORDER Or SWP_NOACTIVATE) End If End If If (m.Msg = WM_NCDESTROY) Then ACWindows.Remove(Handle) End If MyBase.WndProc(m) End Sub End Class End Class
时间: 2024-10-18 21:41:01