写在前面: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原创
添加到百度搜藏
添加到雅虎收藏