Wednesday, April 1, 2009

ComboBox with additional properties for setting the size of the AutoComplete Drop-Down window

/* Represents an ComboBox with additional properties for setting the
size of the AutoComplete Drop-Down window. */
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;


public class ComboBoxExtend : ComboBox
{
private int acDropDownWidth = 170;
private int acDropDownHeight = 106;
private const UInt32 CB_ADDSTRING = 0x85;
public ComboBoxExtend(): base()
{
}
//
/// Provides an encapsulation of an Auto complete drop down window
/// handle and window proc.
///
private class ACWindow : NativeWindow
{
private ComboBoxExtend owner;
private static Dictionary ACWindows = null;
private static List owners = null;

#region "Win API Declarations"
private const UInt32 WM_WINDOWPOSCHANGED = 0x47;
private const UInt32 WM_NCDESTROY = 0x82;
private const UInt32 SWP_NOSIZE = 0x1;
private const UInt32 SWP_NOMOVE = 0x2;
private const UInt32 SWP_NOZORDER = 0x4;
private const UInt32 SWP_NOREDRAW = 0x8;
private const UInt32 SWP_NOACTIVATE = 0x10;

private const UInt32 GA_ROOT = 2;
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public Point Location
{
get { return new Point(this.Left, this.Top); }
}
}
private delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);

[DllImport("user32.dll")]
private static extern IntPtr GetAncestor(IntPtr hWnd, UInt32 gaFlags);

[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();

[DllImport("user32.dll")]
private static extern void GetClassName(System.IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);

[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
#endregion
static ACWindow()
{
ACWindows = new Dictionary();
owners = new List();
}
///
/// Creates a new ACWindow instance from a specific window handle.
///

private ACWindow(IntPtr handle)
{
this.AssignHandle(handle);
}
//public static void test()
//{
// ACWindows = new Dictionary();
// owners = new List();
//}
public static void DestroyOwner(ComboBoxExtend owner)
{
if ((owners.Contains(owner)))
{
owners.Remove(owner);
}
}
///
/// Registers a ComboBoxEx for adjusting the Complete Dropdown window size.
///

public static void RegisterOwner(ComboBoxExtend owner)
{
if ((owners.Contains(owner)))
{
return;
}
//for (int i = 0; i < name ="=">
/// 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.
///
private static bool EnumThreadWindowCallback(IntPtr hWnd, IntPtr lParam)
{
if ((GetClassName(hWnd) == "Auto-Suggest Dropdown"))
{
IntPtr handle = GetAncestor(hWnd, GA_ROOT);
if ((!ACWindows.ContainsKey(handle)))
{
ACWindows.Add(handle, new ACWindow(handle));
}
}
return true;
}
///
/// Gets the class name for a specific window handle.
///

private static string GetClassName(IntPtr hRef)
{
System.Text.StringBuilder lpClassName = new System.Text.StringBuilder(256);
GetClassName(hRef, lpClassName, 256);
return lpClassName.ToString();
}
///
/// Overrides the NativeWindow's WndProc to handle when the window
/// attributes changes.
///

protected override void WndProc(ref System.Windows.Forms.Message m)
{
try
{
if ((m.Msg == WM_WINDOWPOSCHANGED))
{
// 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 == null))
{
Rectangle ownerRect = default(Rectangle);
RECT acRect = new RECT();
foreach (ComboBoxExtend cbo in owners)
{
GetWindowRect(this.Handle, ref acRect);
ownerRect = cbo.RectangleToScreen(cbo.ClientRectangle);
if ((ownerRect.Contains(acRect.Location)))
{
this.owner = cbo;
break; // TODO: might not be correct. Was : Exit For
}
}
owners.Remove(this.owner);
}
if (((owner != null)))
{
SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, owner.AutoCompleteDropDownWidth, owner.AutoCompleteDropDownHeight, SWP_NOMOVE SWP_NOZORDER SWP_NOACTIVATE);
}
}

if ((m.Msg == WM_NCDESTROY))
{
ACWindows.Remove(this.Handle);
}
base.WndProc(ref m);
}
catch
{
}
}
}

}

No comments:

Post a Comment