你的位置是:网站首页--- .Net图形编程---.Net界面控件

非视觉样式下,对ComboBox的重写,在OnMouseLeave时失效


【 字体:


写在前面:ComboBox是GUI编程之中使用比较多的控件,而标准的ComboBox不是很美观,则,需要修改一下外观。这样,就要WndProc(ref Message m)的重写中,对控件进行重画,重写中,可能要使用到ContainsFocus等等的设置属性。同时,在 OnMouseEnter和OnMouseLeave方法中强制控件进行重画。这是比较正常的思路。但是,不知道,你有没有发现这样的一个问题,在ComboBoxStyle设置为DropDown时,控件会出现反应迟缓的现象,也就是鼠标已经移出后,ComboBox没有根据你的要求显示出OnMouseLeave的效果。特别是在显卡内存比较小的时候,这是效果十分的明显。如果你发现了这个问题,或你想更了解这个问题,请看看下面的内容。

效果图
说明:深蓝色是鼠标OnMouseEnter的效果,而浅蓝色是默认的效果。ComboBoxStyle设置为DropDown
 
这一种现象,是不使用视觉样式时,才会发现的,可能视觉样式会帮你修正这个错误,不过,对于很多的业务系统,客户端机器,相信有一部份是不会使用视觉样式的,这种情况下,作为GUIor,还是要解决这一个头大的问题。从现象来看,分明就是OnMouseLeave没有被正常的运行,也就是说,当鼠标离开时,没有加载到相应的代码。可能性有,1,鼠标动作过快了,代码没有反应过来,2,鼠标很快时,而显示卡内存不足,这些GUI编程的代码根本没有运行。

解决的思路
只有主动加插代码以解决这个问题。
加插的代码要能够捕捉这个动作,并且,当ComboBoxStyle设置为DropDown时才运行,
下面是一个方法,是重写OnHandleCreated(EventArgs e)的。
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public extern static IntPtr GetDlgItem(IntPtr hDlg, int nControlID);
        private EditCtrlHook editHook = null;
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            // Hook the edit control
            if (DropDownStyle == ComboBoxStyle.DropDown)
            {
                IntPtr hEditControl = GetDlgItem(Handle, 0x3E9);
                Debug.Assert(hEditControl != IntPtr.Zero, "Fail to get ComboBox's Edit Control Handle...");
                editHook = new EditCtrlHook(this);
                editHook.AssignHandle(hEditControl);
            }
        }
注意到,GetDlgItem(Handle, 0x3E9);是获取ComboBox的句柄,而0x3E9是ComboBox的ControlID,这是固定的,不可以修改。而EditCtrlHook是这样的一个类:
this是重写ComboBox的,如ComboBoxMyFirm就是重写ComboBox,comboBox.ReDrawBox();是ComboBoxMyFirm重画的方法。
实际所做的操作:转入当前控件的句柄,在新的类上面对转入的控件的WM_MOUSELEAVE事件进行重写。RequestMouseLeaveMessage是人工发送鼠标消息。
    internal class EditCtrlHook : System.Windows.Forms.NativeWindow
    {

        ComboBoxMyFirm comboBox = null;
        public EditCtrlHook(ComboBoxMyFirm cb)
        {
            comboBox = cb;
        }

        protected override void WndProc(ref Message m)
        {
            Msg currentMessage = (Msg)m.Msg;

            switch (m.Msg)
            {

                case ((int)Msg.WM_MOUSEMOVE):
                    RequestMouseLeaveMessage(m.HWnd);
                    comboBox.ReDrawBox();
                    break;
                case ((int)Msg.WM_MOUSELEAVE):
                    comboBox.ReDrawBox();
                    break;
                default:
                    break;
            }

            base.WndProc(ref m);

        }
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool TrackMouseEvent(ref TRACKMOUSEEVENTS tme);

        void RequestMouseLeaveMessage(IntPtr hWnd)
        {
            // Crea the structure needed for WindowsAPI call
            TRACKMOUSEEVENTS tme = new TRACKMOUSEEVENTS();

            // Fill in the structure
            tme.cbSize = 16;
            tme.dwFlags = (uint)TrackerEventFlags.TME_LEAVE;
            tme.hWnd = hWnd;
            tme.dwHoverTime = 0;

            // Request that a message gets sent when mouse leaves this window
            TrackMouseEvent(ref tme);
        }
    }


    // Tracker Event Flags
    #region
    public enum TrackerEventFlags : uint
    {
        TME_HOVER = 0x00000001,
        TME_LEAVE = 0x00000002,
        TME_QUERY = 0x40000000,
        TME_CANCEL = 0x80000000
    }
    #endregion

    // TRACKMOUSEEVENTS
    #region
    [StructLayout(LayoutKind.Sequential)]
    public struct TRACKMOUSEEVENTS
    {
        public uint cbSize;
        public uint dwFlags;
        public IntPtr hWnd;
        public uint dwHoverTime;
    }

 


出处:小作坊网ChakMan原创

Copyright © 2006-2008 小作坊网 All rights reserved.
备案号:粤ICP备09058104号          电子信箱: jingle_guan#163.com