Files
App-Installer-For-Windows-8…/WAShell/ModenForm.cs
T
2026-02-07 17:52:36 +08:00

1001 lines
28 KiB
C#

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);
}
}
}