using System; using System.ComponentModel; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; using DataUtils; namespace WAShell { public partial class ModernForm: Form, IMetroIconSupport { // ==================== P/Invoke ==================== private const int WM_NCCALCSIZE = 0x0083; private const int WM_NCHITTEST = 0x0084; private const int WM_NCPAINT = 0x0085; private const int WM_NCACTIVATE = 0x0086; private const int WM_MOUSEMOVE = 0x0200; private const int WM_LBUTTONDOWN = 0x0201; private const int WM_LBUTTONUP = 0x0202; private const int WM_NCLBUTTONDOWN = 0x00A1; private const int WM_NCLBUTTONUP = 0x00A2; private const int WM_PAINT = 0x000F; private const int WM_SETTEXT = 0x000C; private const int WM_SIZE = 0x0005; private const int WM_MOUSELEAVE = 0x02A3; private const int WM_GETMINMAXINFO = 0x0024; private const int WM_DISPLAYCHANGE = 0x007E; private const int HTCLIENT = 1; private const int HTCAPTION = 2; private const int HTCLOSE = 20; private const int HTMAXBUTTON = 9; private const int HTMINBUTTON = 8; private const int HTLEFT = 10; private const int HTRIGHT = 11; private const int HTTOP = 12; private const int HTTOPLEFT = 13; private const int HTTOPRIGHT = 14; private const int HTBOTTOM = 15; private const int HTBOTTOMLEFT = 16; private const int HTBOTTOMRIGHT = 17; private const int CS_DROPSHADOW = 0x00020000; [StructLayout (LayoutKind.Sequential)] private struct MINMAXINFO { public Point ptReserved; public Point ptMaxSize; public Point ptMaxPosition; public Point ptMinTrackSize; public Point ptMaxTrackSize; } [StructLayout (LayoutKind.Sequential)] private struct NCCALCSIZE_PARAMS { [MarshalAs (UnmanagedType.ByValArray, SizeConst = 3)] public RECT [] rgrc; public IntPtr lppos; } [StructLayout (LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; } [StructLayout (LayoutKind.Sequential)] private struct MARGINS { public int cxLeftWidth; public int cxRightWidth; public int cyTopHeight; public int cyBottomHeight; } [DllImport ("user32.dll", SetLastError = true)] private static extern IntPtr GetWindowDC (IntPtr hWnd); [DllImport ("user32.dll")] private static extern int ReleaseDC (IntPtr hWnd, IntPtr hDC); [DllImport ("user32.dll")] private static extern bool GetWindowRect (IntPtr hWnd, out RECT lpRect); [DllImport ("user32.dll")] private static extern bool GetClientRect (IntPtr hWnd, out RECT lpRect); [DllImport ("user32.dll")] private static extern bool ReleaseCapture (); [DllImport ("user32.dll")] private static extern int SendMessage (IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); [DllImport ("user32.dll")] private static extern bool TrackMouseEvent (ref TRACKMOUSEEVENT tme); [DllImport ("user32.dll")] private static extern IntPtr MonitorFromWindow (IntPtr hwnd, int dwFlags); [DllImport ("user32.dll")] private static extern bool GetMonitorInfo (IntPtr hMonitor, ref MONITORINFO lpmi); [DllImport ("dwmapi.dll", PreserveSig = false)] private static extern void DwmExtendFrameIntoClientArea (IntPtr hWnd, ref MARGINS pMarInset); [DllImport ("dwmapi.dll")] private static extern int DwmIsCompositionEnabled (out bool pfEnabled); [StructLayout (LayoutKind.Sequential)] private struct MONITORINFO { public int cbSize; public RECT rcMonitor; public RECT rcWork; public int dwFlags; } [StructLayout (LayoutKind.Sequential)] private struct TRACKMOUSEEVENT { public int cbSize; public int dwFlags; public IntPtr hwndTrack; public int dwHoverTime; } private const int TME_LEAVE = 0x00000002; private const int MONITOR_DEFAULTTONULL = 0; private const int WM_SYSCOMMAND = 0x0112; private const int SC_MOVE = 0xF010; private const int SC_SIZE = 0xF000; // ==================== 字段和属性 ==================== private int _titleBarHeight; private int _borderWidth; private int _resizeAreaWidth = 10; // DPI 适配的尺寸 private int _iconSize; private int _iconOffsetLeft; private int _iconOffsetTop; private int _buttonDisplaySize; private Color _titleBarColorActive = Color.FromArgb (17, 17, 17); private bool _isFormActive = true; private Rectangle _minButtonRect; private Rectangle _maxButtonRect; private Rectangle _closeButtonRect; private Rectangle _iconRect; private bool _isMouseOverMinButton = false; private bool _isMouseOverMaxButton = false; private bool _isMouseOverCloseButton = false; // 按钮按压状态追踪 private bool _isMinButtonPressed = false; private bool _isMaxButtonPressed = false; private bool _isCloseButtonPressed = false; // 资源管理器 private System.ComponentModel.ComponentResourceManager _res; // 按钮资源缓存(原始尺寸) private Bitmap _minNormal, _minLight, _minPress; private Bitmap _maxNormal, _maxLight, _maxPress; private Bitmap _restoreNormal, _restoreLight, _restorePress; private Bitmap _cancelNormal, _cancelLight, _cancelPress; // 缩放后的按钮资源缓存 private Bitmap _minNormalScaled, _minLightScaled, _minPressScaled; private Bitmap _maxNormalScaled, _maxLightScaled, _maxPressScaled; private Bitmap _restoreNormalScaled, _restoreLightScaled, _restorePressScaled; private Bitmap _cancelNormalScaled, _cancelLightScaled, _cancelPressScaled; // 窗口图标 private Icon _windowIcon; private enum ButtonState { Normal, Hover, Pressed } private ButtonState _minState = ButtonState.Normal; private ButtonState _maxState = ButtonState.Normal; private ButtonState _closeState = ButtonState.Normal; private bool _trackingMouse = false; private bool _buttonRectsCalculated = false; // 防止重复的 NCPAINT 请求 private bool _isInNCPaint = false; public ModernForm () { InitializeComponent (); SetStyle (ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.ResizeRedraw, true); this.FormBorderStyle = FormBorderStyle.None; this.DoubleBuffered = false; _res = new System.ComponentModel.ComponentResourceManager (typeof (ModernForm)); UpdateDPIValues (); LoadResourceImages (); ScaleButtonImages (); EnableDWM (); } // ==================== DPI 处理 ==================== private void UpdateDPIValues () { double dpiScale = UITheme.DPIDouble; _titleBarHeight = (int)Math.Round (30 * dpiScale); _borderWidth = (int)Math.Round (1 * dpiScale); _iconSize = (int)Math.Round (24 * dpiScale); _iconOffsetLeft = (int)Math.Round (3 * dpiScale); _iconOffsetTop = (int)Math.Round (3 * dpiScale); _iconSize = _titleBarHeight - _iconOffsetTop * 2; // 按钮显示大小与标题栏等高 _buttonDisplaySize = _titleBarHeight; this.Padding = new Padding (_borderWidth, _titleBarHeight, _borderWidth, _borderWidth); } // ==================== DWM 适配 ==================== private void EnableDWM () { try { // 检查 DWM 是否启用 bool isDwmEnabled = false; if (DwmIsCompositionEnabled (out isDwmEnabled) == 0 && isDwmEnabled) { // 仅禁用标题栏 DWM 绘制,保留 Aero 特性(Aero Snap、Aero Shake 等) MARGINS margins = new MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0, cyBottomHeight = 0 }; DwmExtendFrameIntoClientArea (this.Handle, ref margins); } } catch { // DWM 不可用,继续正常运行 } } // ==================== 资源加载 ==================== private void LoadResourceImages () { try { // 最小化按钮 _minNormal = _res.GetObject ("min") as Bitmap; _minLight = _res.GetObject ("min_light") as Bitmap; _minPress = _res.GetObject ("min_press") as Bitmap; // 最大化按钮 _maxNormal = _res.GetObject ("max") as Bitmap; _maxLight = _res.GetObject ("max_light") as Bitmap; _maxPress = _res.GetObject ("max_press") as Bitmap; // 还原按钮 _restoreNormal = _res.GetObject ("restore") as Bitmap; _restoreLight = _res.GetObject ("restore_light") as Bitmap; _restorePress = _res.GetObject ("restore_press") as Bitmap; // 关闭按钮 _cancelNormal = _res.GetObject ("cancel") as Bitmap; _cancelLight = _res.GetObject ("cancel_light") as Bitmap; _cancelPress = _res.GetObject ("cancel_press") as Bitmap; } catch (Exception ex) { MessageBox.Show ("加载资源失败: " + ex.Message); } } // ==================== 按钮图片 DPI 缩放 ==================== private void ScaleButtonImages () { double dpiScale = UITheme.DPIDouble; int scaledSize = _buttonDisplaySize; try { // 最小化按钮 _minNormalScaled = ScaleBitmap (_minNormal, scaledSize); _minLightScaled = ScaleBitmap (_minLight, scaledSize); _minPressScaled = ScaleBitmap (_minPress, scaledSize); // 最大化按钮 _maxNormalScaled = ScaleBitmap (_maxNormal, scaledSize); _maxLightScaled = ScaleBitmap (_maxLight, scaledSize); _maxPressScaled = ScaleBitmap (_maxPress, scaledSize); // 还原按钮 _restoreNormalScaled = ScaleBitmap (_restoreNormal, scaledSize); _restoreLightScaled = ScaleBitmap (_restoreLight, scaledSize); _restorePressScaled = ScaleBitmap (_restorePress, scaledSize); // 关闭按钮 _cancelNormalScaled = ScaleBitmap (_cancelNormal, scaledSize); _cancelLightScaled = ScaleBitmap (_cancelLight, scaledSize); _cancelPressScaled = ScaleBitmap (_cancelPress, scaledSize); } catch (Exception ex) { MessageBox.Show ("缩放按钮图片失败: " + ex.Message); } } private Bitmap ScaleBitmap (Bitmap original, int targetSize) { if (original == null) return null; if (original.Width == targetSize && original.Height == targetSize) return original; Bitmap scaled = new Bitmap (targetSize, targetSize); using (Graphics g = Graphics.FromImage (scaled)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.DrawImage (original, 0, 0, targetSize, targetSize); } return scaled; } // ==================== 属性 ==================== public Color TitleBarColorActive { get { return _titleBarColorActive; } set { _titleBarColorActive = value; Invalidate (); } } public int ResizeAreaWidth { get { return _resizeAreaWidth; } set { _resizeAreaWidth = value; } } public virtual Icon WindowIcon { get { return _windowIcon; } set { _windowIcon = value; if (this.ClientSize.Width > 0) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } } // ==================== 坐标计算 ==================== private int GetTitleBarWidth () { RECT rcWindow; GetWindowRect (this.Handle, out rcWindow); return rcWindow.right - rcWindow.left - _borderWidth * 2; } private void RecalculateButtonRects () { int titleBarWidth = GetTitleBarWidth (); if (titleBarWidth <= 0) return; // 按钮与标题栏等高 int buttonY = 0; // 顶部对齐 int buttonHeight = _titleBarHeight; // 从右到左排列按钮 int closeButtonX = _borderWidth + titleBarWidth - _buttonDisplaySize; int maxButtonX = closeButtonX - _buttonDisplaySize; int minButtonX = maxButtonX - _buttonDisplaySize; _closeButtonRect = new Rectangle (closeButtonX, buttonY, _buttonDisplaySize, buttonHeight); _maxButtonRect = new Rectangle (maxButtonX, buttonY, _buttonDisplaySize, buttonHeight); _minButtonRect = new Rectangle (minButtonX, buttonY, _buttonDisplaySize, buttonHeight); // 图标位置 _iconRect = new Rectangle ( _borderWidth + _iconOffsetLeft, _borderWidth + (_titleBarHeight - _iconSize) / 2, _iconSize, _iconSize); _buttonRectsCalculated = true; } // ==================== 坐标工具方法 ==================== private Point GetWindowCursorPosition () { RECT rcWindow; GetWindowRect (this.Handle, out rcWindow); int screenX = Control.MousePosition.X; int screenY = Control.MousePosition.Y; int windowX = screenX - rcWindow.left; int windowY = screenY - rcWindow.top; return new Point (windowX, windowY); } private void UpdateButtonHoverState (Point windowPt) { if (!_buttonRectsCalculated) RecalculateButtonRects (); // 保存原来的状态 ButtonState oldMin = _minState; ButtonState oldMax = _maxState; ButtonState oldClose = _closeState; // 更新 hover 状态 _isMouseOverMinButton = _minButtonRect.Contains (windowPt); _isMouseOverMaxButton = _maxButtonRect.Contains (windowPt); _isMouseOverCloseButton = _closeButtonRect.Contains (windowPt); // 更新 ButtonState _minState = _isMinButtonPressed ? ButtonState.Pressed : (_isMouseOverMinButton ? ButtonState.Hover : ButtonState.Normal); _maxState = _isMaxButtonPressed ? ButtonState.Pressed : (_isMouseOverMaxButton ? ButtonState.Hover : ButtonState.Normal); _closeState = _isCloseButtonPressed ? ButtonState.Pressed : (_isMouseOverCloseButton ? ButtonState.Hover : ButtonState.Normal); // 如果状态变化,触发重绘 if (!_isInNCPaint && (oldMin != _minState || oldMax != _maxState || oldClose != _closeState)) { SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } } // ==================== WndProc 处理 ==================== protected override void WndProc (ref Message m) { switch (m.Msg) { case WM_NCCALCSIZE: HandleNCCalcSize (ref m); return; case WM_GETMINMAXINFO: HandleGetMinMaxInfo (ref m); return; case WM_NCPAINT: // 防止重复处理 _isInNCPaint = true; try { PaintNonClientArea (); PaintTitleBar (); m.Result = IntPtr.Zero; } finally { _isInNCPaint = false; } return; case WM_NCACTIVATE: _isFormActive = m.WParam.ToInt32 () != 0; base.WndProc (ref m); // 延迟重绘以避免闪烁 if (!_isInNCPaint) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); return; case WM_PAINT: base.WndProc (ref m); return; case WM_SIZE: base.WndProc (ref m); _buttonRectsCalculated = false; Invalidate (); if (!_isInNCPaint) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); return; case WM_NCHITTEST: HandleNCHitTest (ref m); return; case WM_MOUSEMOVE: HandleMouseMove (m); base.WndProc (ref m); return; case WM_NCLBUTTONDOWN: HandleNCMouseDown (m); return; case WM_NCLBUTTONUP: HandleNCMouseUp (m); return; case WM_MOUSELEAVE: HandleMouseLeave (m); base.WndProc (ref m); return; default: base.WndProc (ref m); return; } } private void HandleNCCalcSize (ref Message m) { if (m.WParam != IntPtr.Zero) { NCCALCSIZE_PARAMS nccs = (NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam, typeof (NCCALCSIZE_PARAMS)); // 调整客户区以留出边框空间 nccs.rgrc [0].left += _borderWidth; nccs.rgrc [0].right -= _borderWidth; nccs.rgrc [0].bottom -= _borderWidth; // 关键:不修改顶部,让非客户区承载标题栏 // nccs.rgrc [0].top 保持不变 Marshal.StructureToPtr (nccs, m.LParam, false); } m.Result = IntPtr.Zero; } private void HandleGetMinMaxInfo (ref Message m) { MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure (m.LParam, typeof (MINMAXINFO)); IntPtr hMonitor = MonitorFromWindow (this.Handle, MONITOR_DEFAULTTONULL); if (hMonitor != IntPtr.Zero) { MONITORINFO monitorInfo = new MONITORINFO (); monitorInfo.cbSize = Marshal.SizeOf (monitorInfo); if (GetMonitorInfo (hMonitor, ref monitorInfo)) { int workWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left; int workHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; mmi.ptMaxSize.X = workWidth + _borderWidth * 2; mmi.ptMaxSize.Y = workHeight + _borderWidth; mmi.ptMaxPosition.X = monitorInfo.rcWork.left - _borderWidth; mmi.ptMaxPosition.Y = monitorInfo.rcWork.top; } } Marshal.StructureToPtr (mmi, m.LParam, false); } private void HandleNCHitTest (ref Message m) { if (!_buttonRectsCalculated) RecalculateButtonRects (); Point windowPt = GetWindowCursorPosition (); RECT rcWindow; GetWindowRect (this.Handle, out rcWindow); int windowWidth = rcWindow.right - rcWindow.left; int windowHeight = rcWindow.bottom - rcWindow.top; int corner = _resizeAreaWidth; // 四角 if (windowPt.X < corner && windowPt.Y < corner) { m.Result = (IntPtr)HTTOPLEFT; return; } if (windowPt.X > windowWidth - corner && windowPt.Y < corner) { m.Result = (IntPtr)HTTOPRIGHT; return; } if (windowPt.X < corner && windowPt.Y > windowHeight - corner) { m.Result = (IntPtr)HTBOTTOMLEFT; return; } if (windowPt.X > windowWidth - corner && windowPt.Y > windowHeight - corner) { m.Result = (IntPtr)HTBOTTOMRIGHT; return; } // 边界 if (windowPt.X < corner) { m.Result = (IntPtr)HTLEFT; return; } if (windowPt.X > windowWidth - corner) { m.Result = (IntPtr)HTRIGHT; return; } if (windowPt.Y > windowHeight - corner) { m.Result = (IntPtr)HTBOTTOM; return; } // 标题栏区域 if (windowPt.Y < _borderWidth + _titleBarHeight) { UpdateButtonHoverState (windowPt); m.Result = (IntPtr)HTCAPTION; return; } m.Result = (IntPtr)HTCLIENT; } private void HandleMouseMove (Message m) { if (!_buttonRectsCalculated) RecalculateButtonRects (); Point windowPt = GetWindowCursorPosition (); // 启用 WM_MOUSELEAVE if (!_trackingMouse) { TRACKMOUSEEVENT tme = new TRACKMOUSEEVENT (); tme.cbSize = Marshal.SizeOf (tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = this.Handle; TrackMouseEvent (ref tme); _trackingMouse = true; } bool oldOverMin = _isMouseOverMinButton; bool oldOverMax = _isMouseOverMaxButton; bool oldOverClose = _isMouseOverCloseButton; _isMouseOverMinButton = _minButtonRect.Contains (windowPt); _isMouseOverMaxButton = _maxButtonRect.Contains (windowPt); _isMouseOverCloseButton = _closeButtonRect.Contains (windowPt); // 只要状态变化就重绘标题栏 if (!_isInNCPaint && (oldOverMin != _isMouseOverMinButton || oldOverMax != _isMouseOverMaxButton || oldOverClose != _isMouseOverCloseButton)) { SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } base.WndProc (ref m); // 保留鼠标移动默认处理 } private void HandleNCMouseDown (Message m) { if (!_buttonRectsCalculated) RecalculateButtonRects (); Point windowPt = GetWindowCursorPosition (); if (_minButtonRect.Contains (windowPt)) { _isMinButtonPressed = true; _minState = ButtonState.Pressed; if (!_isInNCPaint) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } else if (_maxButtonRect.Contains (windowPt)) { _isMaxButtonPressed = true; _maxState = ButtonState.Pressed; if (!_isInNCPaint) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } else if (_closeButtonRect.Contains (windowPt)) { _isCloseButtonPressed = true; _closeState = ButtonState.Pressed; if (!_isInNCPaint) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } else { base.WndProc (ref m); } } private void HandleNCMouseUp (Message m) { if (!_buttonRectsCalculated) RecalculateButtonRects (); Point windowPt = GetWindowCursorPosition (); if (_minButtonRect.Contains (windowPt) && _isMinButtonPressed) { this.WindowState = FormWindowState.Minimized; } else if (_maxButtonRect.Contains (windowPt) && _isMaxButtonPressed) { this.WindowState = this.WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized; } else if (_closeButtonRect.Contains (windowPt) && _isCloseButtonPressed) { _isMinButtonPressed = false; _isMaxButtonPressed = false; _isCloseButtonPressed = false; _minState = ButtonState.Normal; _maxState = ButtonState.Normal; _closeState = ButtonState.Normal; if (!_isInNCPaint) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); this.Close (); return; } _isMinButtonPressed = false; _isMaxButtonPressed = false; _isCloseButtonPressed = false; _minState = ButtonState.Normal; _maxState = ButtonState.Normal; _closeState = ButtonState.Normal; if (!_isInNCPaint) SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } private void HandleMouseLeave (Message m) { bool needRedraw = _isMouseOverMinButton || _isMouseOverMaxButton || _isMouseOverCloseButton; _isMouseOverMinButton = false; _isMouseOverMaxButton = false; _isMouseOverCloseButton = false; _minState = _isMinButtonPressed ? ButtonState.Pressed : ButtonState.Normal; _maxState = _isMaxButtonPressed ? ButtonState.Pressed : ButtonState.Normal; _closeState = _isCloseButtonPressed ? ButtonState.Pressed : ButtonState.Normal; if (needRedraw && !_isInNCPaint) { SendMessage (this.Handle, WM_NCPAINT, IntPtr.Zero, IntPtr.Zero); } _trackingMouse = false; } // ==================== 绘制方法 ==================== private void PaintNonClientArea () { IntPtr hdc = GetWindowDC (this.Handle); if (hdc == IntPtr.Zero) return; try { using (Graphics g = Graphics.FromHdc (hdc)) { g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; RECT rcWindow; GetWindowRect (this.Handle, out rcWindow); int windowWidth = rcWindow.right - rcWindow.left; int windowHeight = rcWindow.bottom - rcWindow.top; // 边框颜色 Color borderColor = _isFormActive ? UITheme.GetDwmThemeColor () : Color.FromArgb (177, 177, 177); borderColor = UITheme.GetDwmThemeColor (); int borderW = Math.Max (1, _borderWidth); // 绘制边框(左、右、底) using (Pen pen = new Pen (borderColor, borderW)) { float halfBorder = borderW / 2.0f; // 左边框 g.DrawLine (pen, halfBorder, 0, halfBorder, windowHeight); // 右边框 g.DrawLine (pen, windowWidth - halfBorder, 0, windowWidth - halfBorder, windowHeight); // 底部边框 g.DrawLine (pen, 0, windowHeight - halfBorder, windowWidth, windowHeight - halfBorder); } } } finally { ReleaseDC (this.Handle, hdc); } } private void PaintTitleBar () { if (this.ClientSize.Width <= 0 || _titleBarHeight <= 0) return; if (!_buttonRectsCalculated) { RecalculateButtonRects (); } IntPtr hdc = GetWindowDC (this.Handle); if (hdc == IntPtr.Zero) return; try { using (Graphics g = Graphics.FromHdc (hdc)) { g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; RECT rcWindow; GetWindowRect (this.Handle, out rcWindow); int windowWidth = rcWindow.right - rcWindow.left; // 标题栏绘制区域 int titleBarX = _borderWidth; int titleBarY = 0; int titleBarWidth = windowWidth - _borderWidth * 2; int titleBarHeight = _titleBarHeight; Color titleBarColor = _isFormActive ? _titleBarColorActive : Color.FromArgb (177, 177, 177); // 绘制标题栏背景(完整填充,不留缝隙) using (Brush brush = new SolidBrush (titleBarColor)) { g.FillRectangle (brush, titleBarX, titleBarY, titleBarWidth, titleBarHeight); } // 绘制图标 Icon iconToDraw = _windowIcon ?? this.Icon; if (iconToDraw != null && _iconRect.Width > 0 && _iconRect.Height > 0) { try { Bitmap iconBitmap = iconToDraw.ToBitmap (); Rectangle adjustedIconRect = new Rectangle ( _iconRect.X, _iconRect.Y, _iconSize, _iconSize); g.DrawImage (iconBitmap, adjustedIconRect); iconBitmap.Dispose (); } catch { } } // 绘制标题文本 if (!string.IsNullOrEmpty (this.Text)) { using (Font font = GetTitleFont ()) { SizeF textSize = g.MeasureString (this.Text, font); float textX = titleBarX + (titleBarWidth - textSize.Width) / 2.0f; float textY = titleBarY + (titleBarHeight - textSize.Height) / 2.0f; using (Brush textBrush = new SolidBrush (Color.White)) { g.DrawString (this.Text, font, textBrush, textX, textY); } } } // 绘制按钮 DrawTitleBarButtons (g); } } finally { ReleaseDC (this.Handle, hdc); } } private Font GetTitleFont () { string [] fontNames = { "Microsoft YaHei", "Segoe UI" }; foreach (string fontName in fontNames) { try { using (Font testFont = new Font (fontName, 11, FontStyle.Regular)) { return new Font (fontName, 11, FontStyle.Regular); } } catch { } } return new Font (SystemFonts.DefaultFont ?? new Font ("Arial", 11, FontStyle.Regular), FontStyle.Regular); } private void DrawTitleBarButtons (Graphics g) { Color backgroundColor = _titleBarColorActive; // 绘制最小化按钮 DrawButton (g, _minButtonRect, _minState, _minNormalScaled, _minLightScaled, _minPressScaled, backgroundColor); // 绘制最大化/还原按钮 if (this.WindowState == FormWindowState.Maximized) { DrawButton (g, _maxButtonRect, _maxState, _restoreNormalScaled, _restoreLightScaled, _restorePressScaled, backgroundColor); } else { DrawButton (g, _maxButtonRect, _maxState, _maxNormalScaled, _maxLightScaled, _maxPressScaled, backgroundColor); } // 绘制关闭按钮 DrawButton (g, _closeButtonRect, _closeState, _cancelNormalScaled, _cancelLightScaled, _cancelPressScaled, backgroundColor); } private void DrawButton (Graphics g, Rectangle buttonRect, ButtonState state, Bitmap imgNormal, Bitmap imgLight, Bitmap imgPress, Color backgroundColor) { if (buttonRect.Width <= 0 || buttonRect.Height <= 0) return; // 1. 填充背景色 using (SolidBrush brush = new SolidBrush (backgroundColor)) { g.FillRectangle (brush, buttonRect); } // 2. 选择状态对应的图片 Bitmap imgBitmap = null; if (state == ButtonState.Pressed) imgBitmap = imgPress ?? imgLight ?? imgNormal; else if ((buttonRect == _minButtonRect && _isMouseOverMinButton) || (buttonRect == _maxButtonRect && _isMouseOverMaxButton) || (buttonRect == _closeButtonRect && _isMouseOverCloseButton)) imgBitmap = imgLight ?? imgNormal; else imgBitmap = imgNormal; if (imgBitmap != null) { // 3. 强制转换为标准 Bitmap 并绘制到目标区域 try { using (Bitmap bmp = new Bitmap (imgBitmap.Width, imgBitmap.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { using (Graphics tempG = Graphics.FromImage (bmp)) { tempG.DrawImage (imgBitmap, 0, 0, imgBitmap.Width, imgBitmap.Height); } // 绘制到目标区域并自动缩放 g.DrawImage (bmp, buttonRect); } } catch { } } } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ClassStyle |= CS_DROPSHADOW; return cp; } } protected override void Dispose (bool disposing) { if (disposing) { // 原始资源 _minNormal?.Dispose (); _minLight?.Dispose (); _minPress?.Dispose (); _maxNormal?.Dispose (); _maxLight?.Dispose (); _maxPress?.Dispose (); _restoreNormal?.Dispose (); _restoreLight?.Dispose (); _restorePress?.Dispose (); _cancelNormal?.Dispose (); _cancelLight?.Dispose (); _cancelPress?.Dispose (); // 缩放后的资源 _minNormalScaled?.Dispose (); _minLightScaled?.Dispose (); _minPressScaled?.Dispose (); _maxNormalScaled?.Dispose (); _maxLightScaled?.Dispose (); _maxPressScaled?.Dispose (); _restoreNormalScaled?.Dispose (); _restoreLightScaled?.Dispose (); _restorePressScaled?.Dispose (); _cancelNormalScaled?.Dispose (); _cancelLightScaled?.Dispose (); _cancelPressScaled?.Dispose (); } base.Dispose (disposing); } } }