自定義下拉選單控制元件

王明輝發表於2014-07-19
  1. 問題及需求
  • 輸入漢字或全拼或簡拼均可得到結果(此需求用原生的ComboBox不容易實現)
  • 點選文字框時彈出下拉選單
  • 進入文字框時彈出下拉選單
  • 輸入文字時,如果有結果,則彈出下拉選單
  • 除文字框和下拉選單外,點選任何地方均隱藏下拉選單
  • 單擊下拉選單中的文字,文字出現在文字框,關閉下拉選單
  • 下拉選單出現後,預設選中第一項,第一項高亮
  • 回車後下拉選單中選中的文字出現在文字框中

2.解決思路

  • 用Panel作為容器,裝載ListView,作為下拉選單的資料容器
  • 定義下拉選單顯示方法,並使用+=將其新增到文字框的Enter和Click事件後
  • 使用DataTable的Select方法過濾資料,並將其賦值給ListView的DataSource
  • 使用windows訊息機制過濾訊息,獲得滑鼠所在位置的控制元件,判斷是否文字框和ListView控制元件,如果是,不處理,如果不是,則隱藏下拉選單
  • 文字框中回車時,取ListView選中的項的值,並賦給文字框
3.程式碼
 
以下是核心程式碼:
 
使控制元件所在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);
        }
    }

  

相關文章