📄 comboboxbase.cs
字号:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Diagnostics;
using System.Security;
using System.Runtime.InteropServices;
using UtilityLibrary.General;
using UtilityLibrary.Win32;
namespace UtilityLibrary.WinControls
{
#region Helper Classes
internal class EditCtrlHook : System.Windows.Forms.NativeWindow
{
#region Class Variables
ComboBoxBase comboBox = null;
bool ignoreNextPaintMessage = false;
#endregion
#region Constructors
public EditCtrlHook(ComboBoxBase cb)
{
comboBox = cb;
}
#endregion
#region Overrides
protected override void WndProc(ref Message m)
{
Msg currentMessage = (Msg)m.Msg;
switch(m.Msg)
{
case ((int)Msg.WM_PAINT):
if ( ignoreNextPaintMessage )
{
ignoreNextPaintMessage = false;
return;
}
if ( comboBox.forceUpdate && comboBox.DroppedDown == false )
{
comboBox.forceUpdate = false;
comboBox.ForceUpdate();
}
if ( comboBox.Enabled == false )
{
// Let the edit control do its thing first
base.WndProc(ref m);
// This is going to generate another paint message
// ignore it
ignoreNextPaintMessage = true;
DrawDisableState();
return;
}
break;
case ((int)Msg.WM_MOUSEMOVE):
RequestMouseLeaveMessage(m.HWnd);
if ( comboBox.highlighted == false)
{
using (Graphics g = Graphics.FromHwnd(comboBox.Handle))
{
comboBox.DrawComboBoxBorder(g, ColorUtil.VSNetBorderColor);
comboBox.DrawComboBoxArrowSelected(g, false);
}
}
break;
case ((int)Msg.WM_MOUSELEAVE):
if ( comboBox.highlighted == true && !comboBox.ContainsFocus)
{
using (Graphics g = Graphics.FromHwnd(comboBox.Handle))
{
comboBox.DrawComboBoxBorder(g, SystemColors.Window);
comboBox.DrawComboBoxArrowNormal(g, false);
}
}
break;
default:
break;
}
base.WndProc(ref m);
}
#endregion
#region Implementation
void RequestMouseLeaveMessage(IntPtr hWnd)
{
// Crea the structure needed for WindowsAPI call
Win32.TRACKMOUSEEVENTS tme = new Win32.TRACKMOUSEEVENTS();
// Fill in the structure
tme.cbSize = 16;
tme.dwFlags = (uint)Win32.TrackerEventFlags.TME_LEAVE;
tme.hWnd = hWnd;
tme.dwHoverTime = 0;
// Request that a message gets sent when mouse leaves this window
WindowsAPI.TrackMouseEvent(ref tme);
}
void DrawDisableState()
{
// we are just going to fill the edit area
// with a white background, the combobox
// already does the hard part
using (Graphics g = Graphics.FromHwnd(Handle))
{
RECT rc = new RECT();
WindowsAPI.GetClientRect(Handle, ref rc);
Rectangle clientSize = new Rectangle(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top);
g.FillRectangle(Brushes.White, clientSize);
// Draw text
STRINGBUFFER buffer;
WindowsAPI.GetWindowText(Handle, out buffer, 512);
using ( Brush b = new SolidBrush(SystemColors.ControlDark) )
{
string text = buffer.szText;
Size textSize = TextUtil.GetTextSize(g, text, SystemInformation.MenuFont);
Point pt = new Point(rc.left, rc.top + ( rc.bottom-textSize.Height )/2);
g.DrawString(text, comboBox.Font, b, pt);
}
}
}
#endregion
}
#endregion
/// <summary>
/// Summary description for ComboBoxBase.
/// </summary>
[ToolboxItem(false)]
public class ComboBoxBase : System.Windows.Forms.ComboBox
{
#region Class Variables
private IntPtr mouseHookHandle = IntPtr.Zero;
private GCHandle mouseProcHandle;
private bool toolBarUse = false;
private bool hooked = false;
public const int ARROW_WIDTH = 12;
private EditCtrlHook editHook = null;
internal bool forceUpdate = false;
internal bool highlighted = false;
bool fireOnSelectedIndexChanged = true;
#endregion
#region Constructors
// I wanted to make this constructor either protected
// or internal so that the ComboBoxBase could not be used
// as a stand alone class, however the IDE designer complains about it
// if the constructors are not public
public ComboBoxBase(bool toolBarUse)
{
// Flag to indicate that combo box will be used
// in a toolbar --which means we will use some window hooks
// to reset the focus of the combobox--
this.toolBarUse = toolBarUse;
DrawMode = DrawMode.OwnerDrawFixed;
SetStyle(ControlStyles.AllPaintingInWmPaint|ControlStyles.UserPaint|ControlStyles.DoubleBuffer, true);
// Use Menu font so that the combobox uses the same font as the toolbar buttons
Font = SystemInformation.MenuFont;
// When use in a toolbar we don't need tab stop
TabStop = false;
}
// I wanted to make this constructor either protected
// or internal so that the ComboBoxBase could not be used
// as a stand alone class, however the IDE designer complains about it
// if the constructors are not public
public ComboBoxBase()
{
DrawMode = DrawMode.OwnerDrawFixed;
SetStyle(ControlStyles.AllPaintingInWmPaint
|ControlStyles.UserPaint|ControlStyles.Opaque|ControlStyles.DoubleBuffer, true);
}
#endregion
#region Overrides
protected override void OnPaint(PaintEventArgs pe)
{
// This on paint is only going to happen for the combobox if
// the combobox has been set the style to do all painting
// in the OnPaint event
base.OnPaint(pe);
if ( DropDownStyle == ComboBoxStyle.DropDown )
{
// We will handle the painting from WM_PAINT
return;
}
if (Enabled == false)
{
DrawDisableState();
return;
}
PaintComboBoxBackground(pe.Graphics, SystemColors.Window);
Rectangle rc = ClientRectangle;
if ( SelectedIndex == -1 )
{
if ( Items.Count > 0 )
{
// Select first item as the current item
fireOnSelectedIndexChanged = false;
SelectedIndex = 0;
}
}
DrawComboBoxItemEx( pe.Graphics, rc, SelectedIndex, false, true);
if ( !ContainsFocus )
{
DrawComboBoxBorder(pe.Graphics, SystemColors.Window);
DrawComboBoxArrowNormal(pe.Graphics, true);
}
else
{
DrawComboBoxBorder(pe.Graphics, ColorUtil.VSNetBorderColor);
}
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// Hook the edit control
if ( DropDownStyle == ComboBoxStyle.DropDown )
{
IntPtr hEditControl = WindowsAPI.GetDlgItem(Handle, 0x3E9);
Debug.Assert(hEditControl != IntPtr.Zero, "Fail to get ComboBox's Edit Control Handle...");
editHook = new EditCtrlHook(this);
editHook.AssignHandle(hEditControl);
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
// Draw bitmap strech to the size of the size of the combobox
Graphics g = e.Graphics;
Rectangle bounds = e.Bounds;
bool selected = (e.State & DrawItemState.Selected) > 0;
bool editSel = (e.State & DrawItemState.ComboBoxEdit ) > 0;
if ( e.Index != -1 )
DrawComboBoxItem(g, bounds, e.Index, selected, editSel);
}
protected override void WndProc(ref Message m)
{
bool doPainting = false;
switch(m.Msg)
{
case (int)Msg.WM_PAINT:
doPainting = true;
break;
default:
break;
}
base.WndProc(ref m);
// Now let's do our own painting
// we have to do it after the combox
// does its own painting so that we can
// let the edit control in the combobox
// take care of the text
if ( doPainting )
ForcePaint(ref m);
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
Graphics g = CreateGraphics();
DrawComboBoxBorder(g,ColorUtil.VSNetBorderColor);
DrawComboBoxArrowSelected(g, false);
g.Dispose();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
if ( !ContainsFocus )
{
Graphics g = CreateGraphics();
DrawComboBoxBorder(g, SystemColors.Window);
DrawComboBoxArrowNormal(g, false);
g.Dispose();
}
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
Graphics g = CreateGraphics();
DrawComboBoxBorder(g, SystemColors.Window);
DrawComboBoxArrowNormal(g, false);
g.Dispose();
if ( toolBarUse && hooked)
{
hooked = false;
EndHook();
}
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
Graphics g = CreateGraphics();
DrawComboBoxBorder(g, ColorUtil.VSNetBorderColor);
DrawComboBoxArrowSelected(g, false);
g.Dispose();
if ( toolBarUse && !hooked)
{
hooked = true;
StartHook();
}
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
if ( fireOnSelectedIndexChanged )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -