分享一个很久之前写的一个Winform换肤组件。
主要利用CBT钩子,NativeWindow来实现。可实现动态换皮肤插件修改窗体显示外观。
我们先定义一个自定义组件
using Skin; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace SkinControl { public class LySkinEngine : Component { #region 字段 public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); private static HookProc _cbtHook; private static IntPtr Hook; private static string m_SkinName = ""; #endregion #region API /// <summary> /// SetWindowsHookEx /// </summary> /// <param name="idHook"></param> /// <param name="lpfn"></param> /// <param name="hMod"></param> /// <param name="dwThreadId"></param> /// <returns></returns> [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, int hMod, int dwThreadId); /// <summary> /// CallNextHookEx /// </summary> /// <param name="hhk"></param> /// <param name="nCode"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); /// <summary> /// UnhookWindowsHookEx /// </summary> /// <param name="hhk"></param> /// <returns></returns> [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern bool UnhookWindowsHookEx(IntPtr hhk); #endregion #region FnHookProc /// <summary> /// FnHookProc /// </summary> /// <param name="nCode"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> private static IntPtr FnHookProc(int nCode, IntPtr wParam, IntPtr lParam) { switch (nCode) { case 5: Control control = Control.FromHandle(wParam); if (control != null) { Skin.SkinResource tmpSkinClass = GetSkin(); FormBase frmBase = new FormBase(control as Form, tmpSkinClass); } break; default: break; } return CallNextHookEx(Hook, nCode, wParam, lParam); } #endregion #region 动态加载皮肤资源 private static SkinResource GetSkin() { SkinResource tmpResource = new SkinResource(); Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + @"Skin" + m_SkinName + @".dll"); Type type = ass.GetType("SkinFile.Skin"); //生成实例 Skin1 Object obj = Activator.CreateInstance(type); //标题背景 PropertyInfo pi = type.GetProperty("CaptionBackgroundColor"); tmpResource.CaptionBackgroundColor = (Color)pi.GetValue(obj, null); //标题前景色 PropertyInfo pi1 = type.GetProperty("CaptionColor"); tmpResource.CaptionColor = (Color)pi1.GetValue(obj, null); return tmpResource; } #endregion public void SetSkin(string varSkinName) { m_SkinName = varSkinName; if (Hook == IntPtr.Zero) { _cbtHook = new HookProc(FnHookProc); Hook = SetWindowsHookEx(5, _cbtHook, 0, AppDomain.GetCurrentThreadId()); Application.ApplicationExit += new EventHandler(Application_ApplicationExit); } } /// <summary> /// Application_ApplicationExit /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Application_ApplicationExit(object sender, EventArgs e) { //Engine.Dispose(false); UnhookWindowsHookEx(Hook); } } }
新增一个皮肤资源类,主要用于存储皮肤文件中的信息
namespace Skin { public class SkinResource { public Color CaptionColor {get;set;} public Color CaptionBackgroundColor {get;set;} } }
新增一个类,主要实现对窗体的消息接管和绘制
namespace Skin { public partial class FormBase : NativeWindow { Form m_f = null; public FormBase(Form varForm, Skin.SkinResource varSkin) { try { m_f = varForm; AssignHandle(m_f.Handle); m_f.HandleDestroyed += new EventHandler(this.OnHandleDestroyed); CloseButtonImage = Resource1.close_normal; CloseButtonHoverImage = Resource1.close_highlight; CloseButtonPressDownImage = Resource1.close_press; MaximumButtonImage = Resource1.max_normal; MaximumButtonHoverImage = Resource1.max_highlight; MaximumButtonPressDownImage = Resource1.max_press; MaximumNormalButtonImage = Resource1.restore_normal; MaximumNormalButtonHoverImage = Resource1.restore_highlight; MaximumNormalButtonPressDownImage = Resource1.restore_press; MinimumButtonImage = Resource1.min_normal; MinimumButtonHoverImage = Resource1.min_highlight; MinimumButtonPressDownImage = Resource1.min_press; HelpButtonImage = Resource1.skin_normal; HelpButtonHoverImage = Resource1.skin_highlight; HelpButtonPressDownImage = Resource1.skin_press; CaptionColor = varSkin.CaptionColor; CaptionBackgroundColor = varSkin.CaptionBackgroundColor; } catch(Exception ex) { } } #region 字段 struct _NonClientSizeInfo { public Size CaptionButtonSize; public Size BorderSize; public int CaptionHeight; public Rectangle CaptionRect; public Rectangle Rect; public Rectangle ClientRect; public int Width; public int Height; }; #region 常量 const int WM_NCACTIVATE = 0x86; const int WM_NCPAINT = 0x85; const int WM_NCLBUTTONDOWN = 0xA1; const int WM_NCRBUTTONDOWN = 0x00A4; const int WM_NCRBUTTONUP = 0x00A5; const int WM_NCMOUSEMOVE = 0x00A0; const int WM_NCLBUTTONUP = 0x00A2; const int WM_NCCALCSIZE = 0x0083; const int WM_NCMOUSEHOVER = 0x02A0; const int WM_NCMOUSELEAVE = 0x02A2; const int WM_NCHITTEST = 0x0084; const int WM_NCCREATE = 0x0081; //const int WM_RBUTTONUP = 0x0205; const int WM_LBUTTONDOWN = 0x0201; const int WM_CAPTURECHANGED = 0x0215; const int WM_LBUTTONUP = 0x0202; const int WM_SETCURSOR = 0x0020; const int WM_CLOSE = 0x0010; const int WM_SYSCOMMAND = 0x0112; const int WM_MOUSEMOVE = 0x0200; const int WM_SIZE = 0x0005; const int WM_SIZING = 0x0214; const int WM_GETMINMAXINFO = 0x0024; const int WM_ENTERSIZEMOVE = 0x0231; const int WM_WINDOWPOSCHANGING = 0x0046; // FOR WM_SIZING MSG WPARAM const int WMSZ_BOTTOM = 6; const int WMSZ_BOTTOMLEFT = 7; const int WMSZ_BOTTOMRIGHT = 8; const int WMSZ_LEFT = 1; const int WMSZ_RIGHT = 2; const int WMSZ_TOP = 3; const int WMSZ_TOPLEFT = 4; const int WMSZ_TOPRIGHT = 5; // left mouse button is down. const int MK_LBUTTON = 0x0001; const int SC_CLOSE = 0xF060; const int SC_MAXIMIZE = 0xF030; const int SC_MINIMIZE = 0xF020; const int SC_RESTORE = 0xF120; const int SC_CONTEXTHELP = 0xF180; const int HTCAPTION = 2; const int HTCLOSE = 20; const int HTHELP = 21; const int HTMAXBUTTON = 9; const int HTMINBUTTON = 8; const int HTTOP = 12; const int SM_CYBORDER = 6; const int SM_CXBORDER = 5; const int SM_CYCAPTION = 4; const int CS_DropSHADOW = 0x20000; const int GCL_STYLE = (-26); #endregion #endregion #region windows api [DllImport("User32.dll")] private static extern IntPtr GetWindowDC(IntPtr hwnd); [DllImport("User32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetWindowRect(IntPtr hwnd, ref Rectangle rect); [DllImport("User32.dll")] private static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int SetClassLong(IntPtr hwnd, int nIndex, int dwNewLong); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern int GetClassLong(IntPtr hwnd, int nIndex); #endregion #region 构造函数 internal void OnHandleCreated(object sender, EventArgs e) { AssignHandle(((Form)sender).Handle); } internal void OnHandleDestroyed(object sender, EventArgs e) { ReleaseHandle(); } #endregion #region 属性 [Category("ControlBox")] [Description("Close button image in control box.")] [DisplayName("CloseButtonImage")] [DesignOnly(true)] public Image CloseButtonImage { get; set; } [Category("ControlBox")] [Description("Close button image pressed down in control box.")] [DisplayName("CloseButtonPressDownImage")] [DesignOnly(true)] public Image CloseButtonPressDownImage { get; set; } [Category("ControlBox")] [Description("Close button image hover in control box.")] [DisplayName("CloseButtonHoverImage")] [DesignOnly(true)] public Image CloseButtonHoverImage { get; set; } [Category("ControlBox")] [Description("Maximum button image in control box.")] [DisplayName("MaximumButtonImage")] [DesignOnly(true)] public Image MaximumButtonImage { get; set; } [Category("ControlBox")] [Description("Maximum button hover image in control box.")] [DisplayName("MaximumButtonHoverImage")] [DesignOnly(true)] public Image MaximumButtonHoverImage { get; set; } [Category("ControlBox")] [Description("Maximum button pressed down image in control box.")] [DisplayName("MaximumButtonPressDownImage")] [DesignOnly(true)] public Image MaximumButtonPressDownImage { get; set; } [Category("ControlBox")] [Description("Maximum Normal button image in control box.")] [DisplayName("MaximumNormalButtonImage")] [DesignOnly(true)] public Image MaximumNormalButtonImage { get; set; } [Category("ControlBox")] [Description("Maximum Normal button hover image in control box.")] [DisplayName("MaximumNormalButtonHoverImage")] [DesignOnly(true)] public Image MaximumNormalButtonHoverImage { get; set; } [Category("ControlBox")] [Description("Maximum Normal button pressed down image in control box.")] [DisplayName("MaximumNormalButtonPressDownImage")] [DesignOnly(true)] public Image MaximumNormalButtonPressDownImage { get; set; } [Category("ControlBox")] [Description("Minimum button image in control box.")] [DisplayName("MinimumButtonImage")] [DesignOnly(true)] public Image MinimumButtonImage { get; set; } [Category("ControlBox")] [Description("Minimum button hover image in control box.")] [DisplayName("MinimumButtonHoverImage")] [DesignOnly(true)] public Image MinimumButtonHoverImage { get; set; } [Category("ControlBox")] [Description("Minimum button pressed down image in control box.")] [DisplayName("MinimumButtonPressDownImage")] [DesignOnly(true)] public Image MinimumButtonPressDownImage { get; set; } [Category("ControlBox")] [Description("Help button image in control box.")] [DisplayName("HelpButtonImage")] [DesignOnly(true)] public Image HelpButtonImage { get; set; } [Category("ControlBox")] [Description("Help button hover image in control box.")] [DisplayName("HelpButtonHoverImage")] [DesignOnly(true)] public Image HelpButtonHoverImage { get; set; } [Category("ControlBox")] [Description("Help button pressed down image in control box.")] [DisplayName("HelpButtonPressDownImage")] [DesignOnly(true)] public Image HelpButtonPressDownImage { get; set; } [Category("CaptionColor")] [Description("The color of caption.")] [DisplayName("CaptionColor")] [DefaultValue(typeof(Color), "Black")] [Browsable(true)] public Color CaptionColor { get; set; } [Category("CaptionColor")] [Description("The color of caption.")] [DisplayName("CaptionBackgroundColor")] [DefaultValue(typeof(Color), "Black")] [Browsable(true)] public Color CaptionBackgroundColor { get; set; } [DefaultValue("")] [Browsable(true)] [Category("ControlBox")] public virtual ContextMenuStrip CaptionContextMenu { get; set; } #endregion #region 方法 private _NonClientSizeInfo GetNonClientInfo(IntPtr hwnd) { _NonClientSizeInfo info = new _NonClientSizeInfo(); info.CaptionButtonSize = SystemInformation.CaptionButtonSize; info.CaptionHeight = SystemInformation.CaptionHeight; switch (m_f.FormBorderStyle) { case System.Windows.Forms.FormBorderStyle.Fixed3D: info.BorderSize = SystemInformation.FixedFrameBorderSize; break; case System.Windows.Forms.FormBorderStyle.FixedDialog: info.BorderSize = SystemInformation.FixedFrameBorderSize; break; case System.Windows.Forms.FormBorderStyle.FixedSingle: info.BorderSize = SystemInformation.FixedFrameBorderSize; break; case System.Windows.Forms.FormBorderStyle.FixedToolWindow: info.BorderSize = SystemInformation.FixedFrameBorderSize; info.CaptionButtonSize = SystemInformation.ToolWindowCaptionButtonSize; info.CaptionHeight = SystemInformation.ToolWindowCaptionHeight; break; case System.Windows.Forms.FormBorderStyle.Sizable: info.BorderSize = SystemInformation.FrameBorderSize; break; case System.Windows.Forms.FormBorderStyle.SizableToolWindow: info.CaptionButtonSize = SystemInformation.ToolWindowCaptionButtonSize; info.BorderSize = SystemInformation.FrameBorderSize; info.CaptionHeight = SystemInformation.ToolWindowCaptionHeight; break; default: info.BorderSize = SystemInformation.BorderSize; break; } Rectangle areatRect = new Rectangle(); GetWindowRect(hwnd, ref areatRect); int width = areatRect.Right - areatRect.Left; int height = areatRect.Bottom - areatRect.Top; info.Width = width; info.Height = height; Point xy = new Point(areatRect.Left, areatRect.Top); xy.Offset(-areatRect.Left, -areatRect.Top); info.CaptionRect = new Rectangle(xy.X, xy.Y + info.BorderSize.Height, width, info.CaptionHeight); info.Rect = new Rectangle(xy.X, xy.Y, width, height); info.ClientRect = new Rectangle(xy.X + info.BorderSize.Width, xy.Y + info.CaptionHeight + info.BorderSize.Height, width - info.BorderSize.Width * 2, height - info.CaptionHeight - info.BorderSize.Height * 2); return info; } private void DrawTitle(Graphics g, _NonClientSizeInfo ncInfo, bool active) { try { int titleX; if (m_f.ShowIcon && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.FixedToolWindow && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow) { Size iconSize = SystemInformation.SmallIconSize; g.DrawIcon(m_f.Icon, new Rectangle(new Point(ncInfo.BorderSize.Width+5, ncInfo.BorderSize.Height + (ncInfo.CaptionHeight - iconSize.Height) / 2+5), iconSize)); titleX = ncInfo.BorderSize.Width + iconSize.Width + ncInfo.BorderSize.Width+5; } else { titleX = ncInfo.BorderSize.Width; } SizeF captionTitleSize = g.MeasureString(m_f.Text, SystemFonts.CaptionFont); g.DrawString(m_f.Text, SystemFonts.CaptionFont, new SolidBrush(CaptionColor), new RectangleF(titleX, (ncInfo.BorderSize.Height + ncInfo.CaptionHeight - captionTitleSize.Height) / 2+5, ncInfo.CaptionRect.Width - ncInfo.BorderSize.Width * 2 - SystemInformation.MinimumWindowSize.Width, ncInfo.CaptionRect.Height), StringFormat.GenericTypographic); } catch(Exception ex) { } } private void DrawBorder(Graphics g, _NonClientSizeInfo ncInfo, Brush background, bool active,ref List<Rectangle> varBorders) { int tmpHeight = m_f.Height; int tmpWidth = m_f.Width; if (ncInfo.Rect.Height != tmpHeight) { ncInfo.Rect.Height = tmpHeight + ncInfo.BorderSize.Height; } if (ncInfo.Rect.Width != tmpWidth) { ncInfo.Rect.Width = tmpWidth + ncInfo.BorderSize.Width; } Rectangle borderTop = new Rectangle(ncInfo.Rect.Left, ncInfo.Rect.Top, ncInfo.Rect.Left + ncInfo.Rect.Width, ncInfo.Rect.Top + ncInfo.BorderSize.Height); Rectangle borderLeft = new Rectangle( new Point(ncInfo.Rect.Location.X, ncInfo.Rect.Location.Y + ncInfo.BorderSize.Height), new Size((int)(ncInfo.BorderSize.Width*2), ncInfo.ClientRect.Height + ncInfo.CaptionHeight + ncInfo.BorderSize.Height)); Rectangle borderRight = new Rectangle(ncInfo.Rect.Width- 3*ncInfo.BorderSize.Width, ncInfo.Rect.Top + ncInfo.BorderSize.Height, (int)(ncInfo.BorderSize.Width * 2), ncInfo.ClientRect.Height + ncInfo.CaptionHeight + ncInfo.BorderSize.Height); Rectangle borderBottom = new Rectangle(ncInfo.Rect.Left + ncInfo.BorderSize.Width, ncInfo.Rect.Height - 3*ncInfo.BorderSize.Height, ncInfo.Rect.Width - ncInfo.BorderSize.Width , (int)(ncInfo.BorderSize.Height * 2)); varBorders.Add(borderTop); varBorders.Add(borderLeft); varBorders.Add(borderRight); varBorders.Add(borderBottom); g.FillRectangle(background, borderTop); // left border g.FillRectangle(background, borderLeft); // right border g.FillRectangle(background, borderRight); // bottom border g.FillRectangle(background, borderBottom); } private List<Rectangle> m_Borders = null; private void DrawCaption(IntPtr hwnd, bool active) { m_Borders = new List<Rectangle>(); IntPtr dc; Graphics g; Size iconSize; _NonClientSizeInfo ncInfo; Brush backgroundColor = new SolidBrush(CaptionBackgroundColor); Brush foregroundColor = new SolidBrush(CaptionColor); iconSize = SystemInformation.SmallIconSize; dc = GetWindowDC(hwnd); ncInfo = GetNonClientInfo(hwnd); g = Graphics.FromHdc(dc); Rectangle rc = ncInfo.CaptionRect; rc.Height = (int)(rc.Height + ncInfo.BorderSize.Height); g.FillRectangle(backgroundColor, rc); DrawBorder(g, ncInfo, backgroundColor, active, ref m_Borders); DrawTitle(g, ncInfo, active); DrawControlBox(g, ncInfo, backgroundColor, m_f.ControlBox, m_f.MaximizeBox, m_f.MinimizeBox, m_f.HelpButton); g.Dispose(); ReleaseDC(hwnd, dc); } private void DrawControlBox(Graphics g, _NonClientSizeInfo info, Brush background, bool closeBtn, bool maxBtn, bool minBtn, bool helpBtn) { int tmpHeight = m_f.Height; int tmpWidth = m_f.Width; if (info.CaptionRect.Height > tmpHeight) { info.CaptionRect.Height = tmpHeight; } if (info.CaptionRect.Width > tmpWidth) { info.CaptionRect.Width = tmpWidth; } info.CaptionRect.Height = info.CaptionRect.Height * 2; if (m_f.ControlBox) { int closeBtnPosX = info.CaptionRect.Width - info.BorderSize.Width - info.CaptionButtonSize.Width; int maxBtnPosX = closeBtnPosX - info.CaptionButtonSize.Width; int minBtnPosX = maxBtnPosX - info.CaptionButtonSize.Width; int btnPosY = info.BorderSize.Height + (info.CaptionHeight - info.CaptionButtonSize.Height) / 2; Rectangle btnRect = new Rectangle(new Point(closeBtnPosX, btnPosY), info.CaptionButtonSize); Rectangle maxRect = new Rectangle(new Point(maxBtnPosX, btnPosY), info.CaptionButtonSize); Rectangle minRect = new Rectangle(new Point(minBtnPosX, btnPosY), info.CaptionButtonSize); Brush backgroundColor = new SolidBrush(CaptionBackgroundColor); g.FillRectangle(backgroundColor, btnRect); g.FillRectangle(backgroundColor, maxRect); g.FillRectangle(backgroundColor, minRect); g.DrawImage(CloseButtonImage, btnRect); if (m_f.MaximizeBox || m_f.MinimizeBox) { if (m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.FixedToolWindow && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow) { if (m_f.WindowState == FormWindowState.Maximized) { g.DrawImage(MaximumNormalButtonImage, maxRect); } else { g.DrawImage(MaximumButtonImage, maxRect); } g.DrawImage(MinimumButtonImage, minRect); } } else if (m_f.HelpButton) { if (m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.FixedToolWindow && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow) { g.DrawImage(HelpButtonImage, maxRect); } } } } protected virtual void OnCaptionContextMenu(int x, int y) { if (this.CaptionContextMenu != null) this.CaptionContextMenu.Show(x, y); } #endregion #region 消息 private int m_IsDrawButton = 0; private int LOBYTE(long p) { return (int)(p & 0x0000FFFF); } private int HIBYTE(long p) { return (int)(p >> 16); } [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] protected override void WndProc(ref Message m) { try { if (m == null) { return; } if (m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.None) { switch (m.Msg) { case WM_NCPAINT: DrawCaption(m.HWnd, Form.ActiveForm == m_f); Console.WriteLine(1); if (m_Borders != null && m_Borders.Count > 0) { for (int i = 0; i < m_Borders.Count; i++) { Console.WriteLine(m_Borders[i].Left + "--" + m_Borders[i].Right + "--" + m_Borders[i].Top + "--" + m_Borders[i].Bottom); } } Console.WriteLine("WM_NCPAINT"); return; case WM_NCACTIVATE: Console.WriteLine("WM_NCACTIVATE"); if (m.WParam.ToInt32() > 0) { DrawCaption(m.HWnd, m.WParam.ToInt32() > 0); Console.WriteLine(2); return; } else { break; } case WM_NCRBUTTONDOWN: { int posX, posY; int wp = m.WParam.ToInt32(); long lp = m.LParam.ToInt64(); posX = LOBYTE(lp); posY = HIBYTE(lp); if (wp == HTCAPTION) { Point pt = m_f.PointToClient(new Point(posX, posY)); if (this.CaptionContextMenu != null) { this.CaptionContextMenu.Show(posX, posY); return; } } break; } case WM_SETCURSOR: if (m_f.ControlBox) { int posX, posY; int wp = m.WParam.ToInt32(); long lp = m.LParam.ToInt64(); posX = LOBYTE(lp); posY = HIBYTE(lp); Brush backgroundColor = new SolidBrush(CaptionBackgroundColor); _NonClientSizeInfo ncInfo = GetNonClientInfo(m.HWnd); int tmpHeight = m_f.Height; int tmpWidth = m_f.Width; if (ncInfo.CaptionRect.Height > tmpHeight) { ncInfo.CaptionRect.Height = tmpHeight; } if (ncInfo.CaptionRect.Width > tmpWidth) { ncInfo.CaptionRect.Width = tmpWidth; } IntPtr dc = GetWindowDC(m.HWnd); Graphics g = Graphics.FromHdc(dc); int closeBtnPosX = ncInfo.CaptionRect.Left + ncInfo.CaptionRect.Width - ncInfo.BorderSize.Width - ncInfo.CaptionButtonSize.Width; int maxBtnPosX, minBtnPosX; maxBtnPosX = closeBtnPosX - ncInfo.CaptionButtonSize.Width; minBtnPosX = maxBtnPosX - ncInfo.CaptionButtonSize.Width; int btnPosY = ncInfo.BorderSize.Height + (ncInfo.CaptionHeight - ncInfo.CaptionButtonSize.Height) / 2; Rectangle btnRect = new Rectangle(new Point(closeBtnPosX, btnPosY), ncInfo.CaptionButtonSize); Rectangle maxRect = new Rectangle(new Point(maxBtnPosX, btnPosY), ncInfo.CaptionButtonSize); Rectangle minRect = new Rectangle(new Point(minBtnPosX, btnPosY), ncInfo.CaptionButtonSize); if (posX != HTMAXBUTTON && posX != HTMINBUTTON && posX != HTCLOSE) { Console.WriteLine("不在"); if (m_IsDrawButton <= 3) { m_IsDrawButton++; Console.WriteLine("啊啊"); goto aa; } break; } m_IsDrawButton = 0; Console.WriteLine("在"); aa: g.FillRectangle(backgroundColor, btnRect); g.FillRectangle(backgroundColor, maxRect); g.FillRectangle(backgroundColor, minRect); if (posX != HTCLOSE) { g.DrawImage(CloseButtonImage, btnRect); } else if (System.Windows.Forms.Control.MouseButtons != System.Windows.Forms.MouseButtons.Left) { g.DrawImage(CloseButtonHoverImage, btnRect); } else { g.DrawImage(CloseButtonPressDownImage, btnRect); } if (m_f.MaximizeBox || m_f.MinimizeBox) { if (m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.FixedToolWindow && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow) { if (m_f.WindowState == FormWindowState.Maximized) { if (m_f.MaximizeBox) { if (posX != HTMAXBUTTON) { g.DrawImage(MaximumNormalButtonImage, maxRect); } else if (System.Windows.Forms.Control.MouseButtons != System.Windows.Forms.MouseButtons.Left) { g.DrawImage(MaximumNormalButtonHoverImage, maxRect); } else { g.DrawImage(MaximumNormalButtonPressDownImage, maxRect); } } else { g.DrawImage(MaximumNormalButtonImage, maxRect); } } else { if (m_f.MaximizeBox) { if (posX != HTMAXBUTTON) { g.DrawImage(MaximumButtonImage, maxRect); } else if (System.Windows.Forms.Control.MouseButtons != System.Windows.Forms.MouseButtons.Left) { g.DrawImage(MaximumButtonHoverImage, maxRect); } else { g.DrawImage(MaximumButtonPressDownImage, maxRect); } } else { g.DrawImage(MaximumButtonImage, maxRect); } } if (m_f.MinimizeBox) { if (posX != HTMINBUTTON) { g.DrawImage(MinimumButtonImage, minRect); } else if (System.Windows.Forms.Control.MouseButtons != System.Windows.Forms.MouseButtons.Left) { g.DrawImage(MinimumButtonHoverImage, minRect); } else { g.DrawImage(MinimumButtonPressDownImage, minRect); } } else { g.DrawImage(MinimumButtonImage, minRect); } } } else if (m_f.HelpButton) { if (m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.FixedToolWindow && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow) { if (posX != HTHELP) { g.DrawImage(HelpButtonImage, maxRect); } else if (System.Windows.Forms.Control.MouseButtons != System.Windows.Forms.MouseButtons.Left) { g.DrawImage(HelpButtonHoverImage, maxRect); } else { g.DrawImage(HelpButtonPressDownImage, maxRect); } } } // Application.DoEvents(); g.Dispose(); ReleaseDC(m.HWnd, dc); } break; case WM_NCLBUTTONUP: { int wp = m.WParam.ToInt32(); switch (wp) { case HTCLOSE: m.Msg = WM_SYSCOMMAND; m.WParam = new IntPtr(SC_CLOSE); break; case HTMAXBUTTON: if (m_f.MaximizeBox) { m.Msg = WM_SYSCOMMAND; if (m_f.WindowState == FormWindowState.Maximized) { m.WParam = new IntPtr(SC_RESTORE); } else { m.WParam = new IntPtr(SC_MAXIMIZE); } } break; case HTMINBUTTON: if (m_f.MinimizeBox) { m.Msg = WM_SYSCOMMAND; m.WParam = new IntPtr(SC_MINIMIZE); } break; case HTHELP: m.Msg = WM_SYSCOMMAND; m.WParam = new IntPtr(SC_CONTEXTHELP); break; default: break; } break; } case WM_NCLBUTTONDOWN: if (m_f.ControlBox) { bool ret = false; int posX, posY; int wp = m.WParam.ToInt32(); long lp = m.LParam.ToInt64(); posX = LOBYTE(lp); posY = HIBYTE(lp); _NonClientSizeInfo ncInfo = GetNonClientInfo(m.HWnd); IntPtr dc = GetWindowDC(m.HWnd); Brush backgroundColor = new SolidBrush(CaptionBackgroundColor); Graphics g = Graphics.FromHdc(dc); int closeBtnPosX = ncInfo.CaptionRect.Left + ncInfo.CaptionRect.Width - ncInfo.BorderSize.Width - ncInfo.CaptionButtonSize.Width; int maxBtnPosX, minBtnPosX; int btnPosY = ncInfo.BorderSize.Height + (ncInfo.CaptionHeight - ncInfo.CaptionButtonSize.Height) / 2; maxBtnPosX = closeBtnPosX - ncInfo.CaptionButtonSize.Width; minBtnPosX = maxBtnPosX - ncInfo.CaptionButtonSize.Width; Rectangle btnRect = new Rectangle(new Point(closeBtnPosX, btnPosY), ncInfo.CaptionButtonSize); Rectangle maxRect = new Rectangle(new Point(maxBtnPosX, btnPosY), ncInfo.CaptionButtonSize); Rectangle minRect = new Rectangle(new Point(minBtnPosX, btnPosY), ncInfo.CaptionButtonSize); if (wp != HTMAXBUTTON && wp != HTMINBUTTON && wp != HTCLOSE) { break; } g.FillRectangle(backgroundColor, btnRect); g.FillRectangle(backgroundColor, maxRect); g.FillRectangle(backgroundColor, minRect); if (wp == HTCLOSE) { g.DrawImage(CloseButtonPressDownImage, btnRect); ret = true; } else { g.DrawImage(CloseButtonImage, btnRect); } if (m_f.MaximizeBox || m_f.MinimizeBox) { if (m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.FixedToolWindow) { if (m_f.WindowState == FormWindowState.Maximized) { if (wp == HTMAXBUTTON && m_f.MaximizeBox) { minBtnPosX = maxBtnPosX - ncInfo.CaptionButtonSize.Width; g.DrawImage(MaximumNormalButtonPressDownImage, maxRect); ret = true; } else { g.DrawImage(MaximumNormalButtonImage, maxRect); } } else { if (wp == HTMAXBUTTON && m_f.MaximizeBox) { minBtnPosX = maxBtnPosX - ncInfo.CaptionButtonSize.Width; g.DrawImage(MaximumButtonPressDownImage, maxRect); ret = true; } else { g.DrawImage(MaximumButtonImage, maxRect); } } if (wp == HTMINBUTTON && m_f.MinimizeBox) { g.DrawImage(MinimumButtonPressDownImage, minRect); ret = true; } else { g.DrawImage(MinimumButtonImage, minRect); } } } else if (m_f.HelpButton) { if (m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.FixedToolWindow && m_f.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow) { if (wp == HTHELP) { g.DrawImage(HelpButtonPressDownImage, maxRect); ret = true; } else { g.DrawImage(HelpButtonImage, maxRect); } } } g.Dispose(); ReleaseDC(m.HWnd, dc); if (ret) return; } break; } } try { base.WndProc(ref m); } catch (Exception ex) { } if (m.Msg == WM_NCACTIVATE && m_f.FormBorderStyle != FormBorderStyle.None) { if (m.WParam.ToInt32() <= 0) { DrawCaption(m.HWnd, m.WParam.ToInt32() > 0); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } #endregion } }
新建一个项目,这个项目是皮肤文件。
namespace SkinFile { public class Skin { private Color _CaptionColor=Color.Blue; public Color CaptionColor { get { return _CaptionColor; } set { _CaptionColor = value; } } private Color _CaptionBackgroundColor=Color.Green; public Color CaptionBackgroundColor { get { return _CaptionBackgroundColor; } set { _CaptionBackgroundColor = value; } } } }
主要提供了窗体非客户区背景色和标题文字颜色。我们可以做个皮肤编辑工具,将用户选择的颜色按上面的命名空间和类生成dll文件。
下面进行测试:
将皮肤文件项目编译,生成dll文件放在debug目录下面的Skin文件夹下。
在窗体的构造函数中,调用
LySkinEngine SkinEngine = new LySkinEngine(); SkinEngine.SetSkin("SkinFile");
SetSkin方法的参数是我们皮肤dll文件的名称,我们可以新建多个皮肤文件,在此处动态切换。
运行效果如下
我们修改调用的皮肤名称
LySkinEngine SkinEngine = new LySkinEngine(); SkinEngine.SetSkin("SkinFile1");
效果如下:
基本效果已实现,还需要继续完善。