⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 toolbarex.cs

📁 c#编写的仿OUTLOOK工具条的Winform菜单
💻 CS
📖 第 1 页 / 共 3 页
字号:
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Text;
using System.Diagnostics;
using System.Security;
using UtilityLibrary.Collections;
using UtilityLibrary.Win32;
using UtilityLibrary.General;
using UtilityLibrary.WinControls;
using UtilityLibrary.Menus;

namespace UtilityLibrary.CommandBars
{
	
	public enum BarType
	{
		ToolBar = 0,
		MenuBar = 1
	}
	
	/// <summary>
	/// Summary description for ToolBarEx.
	/// </summary>
	public class ToolBarEx : System.Windows.Forms.Control, IChevron
	{
		
		ToolBarItemCollection items = new ToolBarItemCollection();
		ToolBarItem[] handledItems = new ToolBarItem[0];
		bool[] handledItemsVisible = new bool[0];
		ChevronMenu chevronMenu = new ChevronMenu();
		BarType barType = BarType.ToolBar;
		const int DROWPDOWN_ARROW_WIDTH = 14;
		const int MARGIN = 3;
		const int MENUTEXT_MARGIN = 8;
		ImageList imageList = null;
		bool bGotIsCommonCtrl6 = false;
		bool isCommonCtrl6 = false;

		// To be used only when we have a menubar type
		enum State 
		{ 
			None, 
			Hot, 
			HotTracking 
		}
		State state = State.None;
		State lastState = State.None;
		Point lastMousePosition = new Point(0, 0);
		int trackHotItem = -1;
		int trackNextItem = -1;
		bool trackEscapePressed = false;
		IntPtr hookHandle = IntPtr.Zero;
		bool doKeyboardSelect = false;
		bool useNewRow = true;
		
		public ToolBarEx()
		{
			InitializeToolBar();
		}

		public ToolBarEx(bool useNewRow)
		{
			InitializeToolBar();
			this.useNewRow = useNewRow;
		}

		public ToolBarEx(BarType type)
		{
			barType = type;
			InitializeToolBar();
		}

		public ToolBarEx(BarType type, bool useNewRow)
		{
			barType = type;
			InitializeToolBar();
			this.useNewRow = useNewRow;
		}

		private void InitializeToolBar()
		{
			// We'll let the toolbar to send us messages for drawing
			SetStyle(ControlStyles.UserPaint, false);
			TabStop = false;
			// Always on top
			Dock = DockStyle.Top;
			Attach();
		}


		~ToolBarEx()
		{
			Detach();
		}

		void Attach()
		{
			items.Changed += new EventHandler(Items_Changed);
			
			int count = Items.Count;
			handledItems = new ToolBarItem[count];
			handledItemsVisible = new bool[count];

			for (int i = 0; i < count; i++)
			{
				ToolBarItem item = Items[i];
				item.Changed += new EventHandler(Item_Changed);
				handledItems[i] = item;
				handledItemsVisible[i] = item.Visible;
			}
		}

		void Detach()
		{
			foreach (ToolBarItem item in handledItems)
			{
				item.Changed -= new EventHandler(Item_Changed);
			}
			
			handledItems = null;
			handledItemsVisible = null;
			items.Changed -= new EventHandler(Items_Changed);

		}

		public bool UseNewRow
		{
			get { return useNewRow; }
		}
			
		public ToolBarItemCollection Items
		{
			get { return items; }
		}

		protected override Size DefaultSize
		{
			get { return new Size(1, 1); }
		}

		public BarType BarType
		{
			get { return barType; }

		}

		private bool IsCommonCtrl6()
		{
			// Cache this value for efficenty
			if ( bGotIsCommonCtrl6 == false )
			{			
				DLLVERSIONINFO dllVersion = new DLLVERSIONINFO();
				// We are assummng here that anything greater or equal than 6
				// will have the new XP theme drawing enable
				dllVersion.cbSize = Marshal.SizeOf(typeof(DLLVERSIONINFO));
				WindowsAPI.GetCommonControlDLLVersion(ref dllVersion);
				bGotIsCommonCtrl6 = true;
				isCommonCtrl6 = (dllVersion.dwMajorVersion >= 6);
			}
			return isCommonCtrl6;
		}


		protected override void CreateHandle() 
		{
			// Make sure common control library initilizes toolbars and rebars
			if ( !RecreatingHandle )
			{
				INITCOMMONCONTROLSEX icex = new INITCOMMONCONTROLSEX();
				icex.dwSize = Marshal.SizeOf(typeof(INITCOMMONCONTROLSEX));
				icex.dwICC = (int)(CommonControlInitFlags.ICC_BAR_CLASSES | CommonControlInitFlags.ICC_COOL_CLASSES);
				WindowsAPI.InitCommonControlsEx(icex);
			}
			
			base.CreateHandle();
		}
	
		protected override CreateParams CreateParams
		{
			get
			{
				CreateParams createParams = base.CreateParams;
				createParams.ClassName = WindowsAPI.TOOLBARCLASSNAME;
				createParams.ExStyle = 0;
				// Windows specific flags
				createParams.Style = (int)(WindowStyles.WS_CHILD | WindowStyles.WS_VISIBLE |
					WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_CLIPSIBLINGS);
				// Common Control specific flags
				createParams.Style |= (int)(CommonControlStyles.CCS_NODIVIDER | CommonControlStyles.CCS_NORESIZE | 
					CommonControlStyles.CCS_NOPARENTALIGN);
				// ToolBar specific flags
				createParams.Style |= (int)(ToolBarStyles.TBSTYLE_TOOLTIPS | ToolBarStyles.TBSTYLE_FLAT | ToolBarStyles.TBSTYLE_TRANSPARENT);
				if (HasText()) createParams.Style |= (int)ToolBarStyles.TBSTYLE_LIST;
				
				return createParams;
			}
		}

		private bool HasText()
		{

			for (int i = 0; i < items.Count; i++)
			{
				// check if we need to make this toolbar TBSTYLE_LIST
				if ( items[i].Text != null && items[i].Text != string.Empty )
					return true;
			}
			return false;

		}
	
		protected override void OnHandleCreated(EventArgs e)
		{
			// Send message needed for the toolbar to work properly before any other messages are sent
			WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONSTRUCTSIZE, Marshal.SizeOf(typeof(TBBUTTON)), 0);
			// Setup extended styles
			int extendedStyle = (int)(ToolBarExStyles.TBSTYLE_EX_HIDECLIPPEDBUTTONS | 
				ToolBarExStyles.TBSTYLE_EX_DOUBLEBUFFER );
			if ( BarType == BarType.ToolBar ) extendedStyle |= (int)ToolBarExStyles.TBSTYLE_EX_DRAWDDARROWS;
			WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_SETEXTENDEDSTYLE, 0, extendedStyle);
			RealizeItems();
			base.OnHandleCreated(e);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			if ( barType == BarType.MenuBar)
			{
				Point point = new Point(e.X, e.Y);
				if ( state == State.Hot )
				{
					int index = HitTest(point);
					if ((IsValid(index)) && ( point != lastMousePosition))
						SetHotItem(index);
					return;
				}
				lastMousePosition = point;
			}
			
			base.OnMouseMove(e);
		}

		protected override void OnMouseDown(MouseEventArgs e)
		{
			if ( barType == BarType.MenuBar)
			{
				if ((e.Button == MouseButtons.Left) && (e.Clicks == 1))
				{
					Point point = new Point(e.X, e.Y);
					int index = HitTest(point);
					if (IsValid(index))
					{
						TrackDropDown(index);
						return;
					}
				}
			}
			
			base.OnMouseDown(e);
		}

		bool IsValid(int index)
		{
			int count = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONCOUNT, 0, 0);
			return ((index >= 0) && (index < count));
		}

		int HitTest(Point point)
		{
			POINT pt = new POINT();
			pt.x = point.X;
			pt.y = point.Y;
			int hit = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_HITTEST, 0, ref pt);
			if (hit > 0)
			{
				point = PointToScreen(point);
				Rectangle bounds = RectangleToScreen(new Rectangle(0, 0, Width, Height));
				if ( !bounds.Contains(point) ) return -1;
			}
			return hit;
		}

		int GetNextItem(int index)
		{
			if (index == -1) throw new Exception();
			int count = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONCOUNT, 0, 0);
			index++;
			if (index >= count) index = 0;
			return index;
		}
			
		int GetPreviousItem(int index)
		{
			if (index == -1) throw new Exception();
			int count = WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_BUTTONCOUNT, 0, 0);
			index--;
			if (index < 0) index = count - 1;
			return index;
		}

		int GetHotItemIndex()
		{
			return WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_GETHOTITEM, 0, 0);
		}
		
		void SetHotItem(int index)
		{
			WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_SETHOTITEM, index, 0);
		}

		void TrackDropDown(int index)
		{
				
			while ( index >= 0 )
			{
				trackNextItem = -1;
		
				BeginUpdate();

				// Raise event
				ToolBarItem item = (ToolBarItem)items[index];
				item.RaiseDropDown();
				// Item state
				WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_PRESSBUTTON, index, -1);

				// Trick to get the first menu item selected
				if ( doKeyboardSelect )
				{
					WindowsAPI.PostMessage(Handle, (int)Msg.WM_KEYDOWN, (int) Keys.Down, 1);
					WindowsAPI.PostMessage(Handle, (int)Msg.WM_KEYUP, (int) Keys.Down, 1);
				}
				doKeyboardSelect = false;
				SetState(State.HotTracking, index);

				// Hook
				WindowsAPI.HookProc hookProc = new WindowsAPI.HookProc(DropDownHook);
				GCHandle hookProcHandle = GCHandle.Alloc(hookProc);
				hookHandle = WindowsAPI.SetWindowsHookEx((int)WindowsHookCodes.WH_MSGFILTER, 
					hookProc, IntPtr.Zero, WindowsAPI.GetCurrentThreadId());
				if ( hookHandle == IntPtr.Zero ) throw new SecurityException();

				// Ask for position
				RECT rect = new RECT();
				WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_GETRECT, index, ref rect);
				Point position = new Point(rect.left, rect.bottom-1);
				
				EndUpdate();
				Update();
				CommandBarMenu menu = item.ToolBarItemMenu;
				if ( menu == null ) return;
				menu.Show(this, position);
								
				// Unhook		
				WindowsAPI.UnhookWindowsHookEx(hookHandle);
				hookProcHandle.Free();
				hookHandle = IntPtr.Zero;

				// Item state
				WindowsAPI.SendMessage(Handle, (int)ToolBarMessages.TB_PRESSBUTTON, index, 0);
				SetState(trackEscapePressed ? State.Hot : State.None, index);

				index = trackNextItem;
			}
		}

		void TrackDropDownNext(int index)
		{
			if (index != trackHotItem)
			{
				WindowsAPI.PostMessage(Handle, (int)Msg.WM_CANCELMODE, 0, 0);
				trackNextItem = index;
			}
		}

		IntPtr DropDownHook(int code, IntPtr wparam, IntPtr lparam) 
		{
			if (code == (int)MouseHookFilters.MSGF_MENU)
			{
				MSG msg = (MSG) Marshal.PtrToStructure(lparam, typeof(MSG));
				Message message = Message.Create(msg.hwnd, msg.message, msg.wParam, msg.lParam);
				if ( DropDownFilter(ref message) )
					return (IntPtr) 1;
			}
			return WindowsAPI.CallNextHookEx(hookHandle, code, wparam, lparam);
		}

		bool DropDownFilter(ref Message message)
		{
			if (state != State.HotTracking) throw new Exception();

			// comctl32 sometimes steals the hot item for unknown reasons.
			SetHotItem(trackHotItem);

			if (message.Msg == (int)Msg.WM_KEYDOWN)
			{
				Keys keyData = (Keys)(int) message.WParam | ModifierKeys;
				if ( keyData == Keys.Left || keyData == Keys.Right )
					doKeyboardSelect = true;
                
				if (keyData == Keys.Left)
				{
					TrackDropDownNext(GetPreviousItem(trackHotItem));
					return true;
				}

				// Only move right if there is no submenu on the current selected item.
				ToolBarItem item = items[trackHotItem];
				if ((keyData == Keys.Right) && ((item.ToolBarItemMenu.SelectedMenuItem == null) 
					|| (item.ToolBarItemMenu.SelectedMenuItem.MenuItems.Count == 0)))
				{
					TrackDropDownNext(GetNextItem(trackHotItem));
					return true;
				}

				if (keyData == Keys.Escape)
				{
					trackEscapePressed = true;
				}
			}
			else if ((message.Msg == (int)Msg.WM_MOUSEMOVE) || (message.Msg == (int)Msg.WM_LBUTTONDOWN))
			{
				Point point = new Point(((int) message.LParam) & 0xffff, ((int) message.LParam) >> 16);
				point = this.PointToClient(point);

				if (message.Msg == (int)Msg.WM_MOUSEMOVE)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -