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

📄 popupmenu.cs

📁 c#编写的仿OUTLOOK工具条的Winform菜单
💻 CS
📖 第 1 页 / 共 5 页
字号:
						{
							// Is the mouse event for this popup window?
							if (msg.hwnd != this.Handle)
							{
								// Let the parent chain of PopupMenu's decide if they want it
								if (!ParentWantsMouseMessage(ref msg)&& !child && !combolist)
								{
									// No, then we need to exit the popup menu tracking
									_exitLoop = true;

									// DO NOT process the message, leave it on the queue
									// and let the real destination window handle it.
									leaveMsg = true;

									// Is a parent control specified?
									if (_parentControl != null)
									{
										// Is the mouse event destination the parent control?
										if (msg.hwnd == _parentControl.Handle)
										{
											// Then we want to consume the message so it does not get processed 
											// by the parent control. Otherwise, pressing down will cause this 
											// popup to disappear but the message will then get processed by 
											// the parent and cause a popup to reappear again. When we actually
											// want the popup to disappear and nothing more.
											leaveMsg = false;
										}
									}
								}
							}
						}
						else
						{	
							// Mouse move occured
							if (msg.message == (int)Msg.WM_MOUSEMOVE) 
							{
								// Is the mouse event for this popup window?
								if (msg.hwnd != this.Handle)
								{
									// Do we still think the mouse is over our window?
									if (_mouseOver)
									{
										// Process mouse leaving situation
										OnWM_MOUSELEAVE();
									}

									// Let the parent chain of PopupMenu's decide if they want it
									if (!ParentWantsMouseMessage(ref msg) && !child && !combolist)
									{
										// Eat the message to prevent the destination getting it
										Win32.MSG eat = new Win32.MSG();
										WindowsAPI.GetMessage(ref eat, 0, 0, 0);

										// Do not attempt to pull a message off the queue as it has already
										// been eaten by us in the above code
										leaveMsg = true;
									}
								}
							}
							else
							{
								// Was the alt key pressed?
								if (msg.message == (int)Msg.WM_SYSKEYDOWN)
								{
									// Alt key pressed on its own
									if((int)msg.wParam == (int)Win32.VirtualKeys.VK_MENU)	// ALT key
									{
										// Then we should dimiss ourself
										_exitLoop = true;
									}
								}

								// Was a key pressed?
								if (msg.message == (int)Msg.WM_KEYDOWN)
								{
									switch((int)msg.wParam)
									{
									case (int)Win32.VirtualKeys.VK_UP:
										ProcessKeyUp();
										break;
									case (int)Win32.VirtualKeys.VK_DOWN:
										ProcessKeyDown();
										break;
									case (int)Win32.VirtualKeys.VK_LEFT:
										ProcessKeyLeft();
										break;
									case (int)Win32.VirtualKeys.VK_RIGHT:
										if(ProcessKeyRight())
										{
											// Do not attempt to pull a message off the queue as the
											// ProcessKeyRight has eaten the message for us
											leaveMsg = true;
										}
										break;
									case (int)Win32.VirtualKeys.VK_RETURN:
										// Is an item currently selected
										if (_trackItem != -1)
										{
											DrawCommand dc = _drawCommands[_trackItem] as DrawCommand;

											// Does this item have a submenu?
											if (dc.SubMenu)
											{
												// Consume the keyboard message to prevent the submenu immediately
												// processing the same message again. Remember this routine is called
												// after PeekMessage but the message is still on the queue at this point
												Win32.MSG eat = new Win32.MSG();
												WindowsAPI.GetMessage(ref eat, 0, 0, 0);

												// Handle the submenu
												OperateSubMenu(_trackItem, false);

												// Do not attempt to pull a message off the queue as it has already
												// been eaten by us in the above code
												leaveMsg = true;
											}
											else
											{
												// Is this item the expansion command?
												if (dc.Expansion)
												{
													RegenerateExpansion();
												}
												else
												{
													// Define the selection to return to caller
													_returnCommand = dc.MenuCommand;

													// Finish processing messages
													_exitLoop = true;	
												}
											}
										}
										break;
									case (int)Win32.VirtualKeys.VK_ESCAPE:
										// User wants to exit the menu, so set the flag to exit the message loop but 
										// let the message get processed. This way the key press is thrown away.
										_exitLoop = true;
										break;
									default:
										// Any other key is treated as a possible mnemonic
										int selectItem = ProcessMnemonicKey((char)msg.wParam);

										if (selectItem != -1)
										{
											DrawCommand dc = _drawCommands[selectItem] as DrawCommand;

											// Define the selection to return to caller
											_returnCommand = dc.MenuCommand;

											// Finish processing messages
											_exitLoop = true;	
										}
										break;
									}
								}
							}
						}
							
						// Should the message we pulled from the queue?
						if (!leaveMsg)
						{
							if (WindowsAPI.GetMessage(ref msg, 0, 0, 0))
							{
								WindowsAPI.TranslateMessage(ref msg);
								WindowsAPI.DispatchMessage(ref msg);
							}
						}
						else
							leaveMsg = false;
					}
				}
			}	

			// Do we have a focus we need to restore?
			if (_oldFocus != IntPtr.Zero)
				ReturnTheFocus();

			// Need to unset this window as the parent of the comboboxes
			// -- if any -- otherwise the combobox use in an toolbar would get "sick"
			UnsetComboBoxesParent();

			// Hide the window from view before killing it, as sometimes there is a
			// short delay between killing it and it disappearing because of the time
			// it takes for the destroy messages to get processed
			WindowsAPI.ShowWindow(this.Handle, (short)Win32.ShowWindowStyles.SW_HIDE);
	
			// Commit suicide
			DestroyHandle();

			// Was a command actually selected?
			if ((_parentMenu == null) && (_returnCommand != null))
			{
				// Pulse the selected event for the command
				_returnCommand.OnClick(EventArgs.Empty);
			}

			return _returnCommand;
		}

		public void Dismiss()
		{
			if (this.Handle != IntPtr.Zero)
			{
				// Prevent the timer from expiring
				_timer.Stop();

				// Kill any child menu
				if (_childMenu != null)
					_childMenu.Dismiss();

				// Finish processing messages
				_exitLoop = true;	

				// Hide ourself
				WindowsAPI.ShowWindow(this.Handle, (short)Win32.ShowWindowStyles.SW_HIDE);

				// Cause our own message loop to exit
				WindowsAPI.PostMessage(this.Handle, WM_DISMISS, 0, 0); 
			}
		}

		protected void CreateAndShowWindow()
		{
			// Decide if we need layered windows
			_layered = (_supportsLayered && (_style == VisualStyle.IDE));
			
			// Don't use layered windows because we would need to do more work
			// to paint the comboboxes
			_layered = false;

			// Process the menu commands to determine where each one needs to be
			// drawn and return the size of the window needed to display it.
			Size winSize = GenerateDrawPositions();

			Point screenPos = CorrectPositionForScreen(winSize);

			CreateParams cp = new CreateParams();

			// Any old title will do as it will not be shown
			cp.Caption = "NativePopupMenu";
			
			// Define the screen position/size
			cp.X = screenPos.X;
			cp.Y = screenPos.Y;
			cp.Height = winSize.Height;
			cp.Width = winSize.Width;

			// As a top-level window it has no parent
			cp.Parent = IntPtr.Zero;
			
			// Appear as a top-level window
			cp.Style = unchecked((int)(uint)Win32.WindowStyles.WS_POPUP |
				(int)(uint)Win32.WindowStyles.WS_CLIPCHILDREN);
			
			// Set styles so that it does not have a caption bar and is above all other 
			// windows in the ZOrder, i.e. TOPMOST
			cp.ExStyle = (int)Win32.WindowExStyles.WS_EX_TOPMOST + (int)Win32.WindowExStyles.WS_EX_TOOLWINDOW;

			// OS specific style
			if (_layered)
			{
				// If not on NT then we are going to use alpha blending on the shadow border
				// and so we need to specify the layered window style so the OS can handle it
				cp.ExStyle += (int)Win32.WindowExStyles.WS_EX_LAYERED;
			}

			// Is this the plain style of appearance?
			if (_style == VisualStyle.Plain)
			{
				// We want the tradiditonal 3D border
				cp.Style += unchecked((int)(uint)Win32.WindowStyles.WS_DLGFRAME);
			}

			// Create the actual window
			this.CreateHandle(cp);

			// Update the window clipping region
			if (!_layered)
				SetWindowRegion(winSize);	
		
            // Make sure comboboxes are the children of this window
		    SetComboBoxesParent();

			// Show the window without activating it (i.e. do not take focus)
			WindowsAPI.ShowWindow(this.Handle, (short)Win32.ShowWindowStyles.SW_SHOWNOACTIVATE);

			if (_layered)
			{
				// Remember the correct screen drawing details
				_currentPoint = screenPos;
				_currentSize = winSize;

				// Update the image for display
				UpdateLayeredWindow();

				// Must grab the focus immediately
				if (_grabFocus)
					GrabTheFocus();
			}
		}

		void SetComboBoxesParent()
		{
			foreach(MenuCommand command in _menuCommands)
			{
                // no need for recursion, comboboxes are only 
				// on the first level
				if ( command.ComboBox != null)
				{
					WindowsAPI.SetParent(command.ComboBox.Handle, Handle);
				}
			}
		}

		void UnsetComboBoxesParent()
		{
			foreach(MenuCommand command in _menuCommands)
			{
				// no need for recursion, comboboxes are only 
				// on the first level
				if ( command.ComboBox != null)
				{
					command.ComboBox.Visible = false;
					WindowsAPI.SetParent(command.ComboBox.Handle, IntPtr.Zero);
				}
			}
		}

		bool IsComboBoxList(IntPtr hWnd)
		{
			STRINGBUFFER className;
			WindowsAPI.GetClassName(hWnd, out className, 80);
			if ( className.szText == "ComboLBox" )
				return true;
			return false;

		}

		protected void UpdateLayeredWindow()
		{
			UpdateLayeredWindow(_currentPoint, _currentSize);
		}

		protected void UpdateLayeredWindow(Point point, Size size)
		{
			// Create bitmap for drawing onto
			Bitmap memoryBitmap = new Bitmap(size.Width, size.Height, PixelFormat.Format32bppArgb);

			using(Graphics g = Graphics.FromImage(memoryBitmap))
			{
				Rectangle area = new Rectangle(0, 0, size.Width, size.Height);
		
				// Draw the background area
				DrawBackground(g, area);

				// Draw the actual menu items
				DrawAllCommands(g);

				// Get hold of the screen DC
				IntPtr hDC = WindowsAPI.GetDC(IntPtr.Zero);								// Create a memory based DC compatible with the screen DC				IntPtr memoryDC = WindowsAPI.CreateCompatibleDC(hDC);								// Get access to the bitmap handle contained in the Bitmap object				IntPtr hBitmap = memoryBitmap.GetHbitmap(Color.FromArgb(0));				// Select this bitmap for updating the window presentation				IntPtr oldBitmap = WindowsAPI.SelectObject(memoryDC, hBitmap);				// New window size				Win32.SIZE ulwsize;				ulwsize.cx = size.Width;				ulwsize.cy = size.Height;				// New window position				Win32.POINT topPos;				topPos.x = point.X;				topPos.y = point.Y;				// Offset into memory bitmap is always zero				Win32.POINT pointSource;				pointSource.x = 0;				pointSource.y = 0;				// We want to make the entire bitmap opaque 				Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();				blend.BlendOp             = (byte)Win32.AlphaFlags.AC_SRC_OVER;				blend.BlendFlags          = 0;				blend.SourceConstantAlpha = 255;				blend.AlphaFormat         = (byte)Win32.AlphaFlags.AC_SRC_ALPHA;				// Tell operating system to use our bitmap for painting				WindowsAPI.UpdateLayeredWindow(Handle, hDC, ref topPos, ref ulwsize, 										   memoryDC, ref pointSource, 0, ref blend, 										   (int)Win32.UpdateLayeredWindowsFlags.ULW_ALPHA);
				// Put back the old bitmap handle
				WindowsAPI.SelectObject(memoryDC, oldBitmap);				// Cleanup resources				WindowsAPI.ReleaseDC(IntPtr.Zero, hDC);				WindowsAPI.DeleteObject(hBitmap);				WindowsAPI.DeleteDC(memoryDC);			}		}

		protected void SetWindowRegion(Size winSize)
		{
			// Style specific handling
			if (_style == VisualStyle.IDE)
			{
				int shadowHeight = _position[(int)_style, (int)PI.ShadowHeight];
				int shadowWidth = _position[(int)_style, (int)PI.ShadowWidth];

				// Create a new region object

⌨️ 快捷键说明

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