- 問題及需求
- 輸入漢字或全拼或簡拼均可得到結果(此需求用原生的ComboBox不容易實現)
- 點選文字框時彈出下拉選單
- 進入文字框時彈出下拉選單
- 輸入文字時,如果有結果,則彈出下拉選單
- 除文字框和下拉選單外,點選任何地方均隱藏下拉選單
- 單擊下拉選單中的文字,文字出現在文字框,關閉下拉選單
- 下拉選單出現後,預設選中第一項,第一項高亮
- 回車後下拉選單中選中的文字出現在文字框中
2.解決思路
- 用Panel作為容器,裝載ListView,作為下拉選單的資料容器
- 定義下拉選單顯示方法,並使用+=將其新增到文字框的Enter和Click事件後
- 使用DataTable的Select方法過濾資料,並將其賦值給ListView的DataSource
- 使用windows訊息機制過濾訊息,獲得滑鼠所在位置的控制元件,判斷是否文字框和ListView控制元件,如果是,不處理,如果不是,則隱藏下拉選單
- 文字框中回車時,取ListView選中的項的值,並賦給文字框
以下是核心程式碼:
使控制元件所在form繼承IMessageFilter,並實現bool PreFilterMessage(ref Message m)方法
public bool PreFilterMessage(ref System.Windows.Forms.Message message) { int hwnd = 0; StringBuilder winText = new StringBuilder(); StringBuilder clsName = new StringBuilder(); StringBuilder pText = new StringBuilder(); //獲取滑鼠所在位置獲取窗體或控制元件的資訊,包括Handle,窗體(控制元件)的標題,窗體(控制元件)的類名,父容器的標題 APImouse.GetWindowFromPoint(ref hwnd, ref winText, ref clsName, ref pText); // 滑鼠左鍵訊息 if (message.Msg >= 513 && message.Msg <= 515) { if (hwnd != (int)listBox1.Handle && hwnd != (int)tbBrand.Handle) pnlBrandList.Visible = false; } return false; } public struct POINT { public int x; public int y; } public class APImouse { [DllImport("user32.dll", EntryPoint = "GetCursorPos")] public static extern int GetCursorPos(ref POINT lpPoint); [DllImport("user32.dll", EntryPoint = "WindowFromPoint")]//指定座標處窗體控制程式碼 public static extern int WindowFromPoint(int xPoint, int yPoint); [DllImport("user32.dll", EntryPoint = "GetWindowText")]//指定座標處窗體標題 public static extern int GetWindowText(int hwnd, string lpString, int cch); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern int GetParent(int hWnd); public static void GetWindowFromPoint(ref int hwnd, ref StringBuilder winText, ref StringBuilder clsName, ref StringBuilder pText) { int parentHandle = 0; int maxLen = 128; POINT pnt = new POINT(); parentHandle = GetCursorPos(ref pnt); hwnd = WindowFromPoint(pnt.x, pnt.y); winText = new StringBuilder(maxLen); parentHandle = GetWindowText(hwnd, winText.ToString(), maxLen); clsName = new StringBuilder(maxLen); parentHandle = GetClassName(hwnd, clsName, maxLen); pText = new StringBuilder(maxLen); parentHandle = GetParent(hwnd); parentHandle = GetWindowText(parentHandle, pText.ToString(), maxLen); } }