很久沒來博客園,今天搗鼓到如今就是爲了把以前的皮膚控件完善好,windows
以前也看了不少技術文章,大多數都是本身重寫系統控件實現換膚,幾乎沒有像東日的(IrisSkin)控件同樣 添加一個組件 把系統的皮膚全換掉,我曾經也是重寫系統的控件,但我就喜歡瞎搗鼓,因而就開始找這方面的資料,苦於沒學過底層,對windows窗口 以及消息循環機制不瞭解,找資料也基本上白搭了許久,但最後覺得本身能想到的最笨的方法實現 了繼承了本身寫的父窗口,那麼窗口添加的控件就是本身畫的 而不是系統畫的,ide
先上傳一張效果圖:this
成天效果應該也還算勉強吧,目前我也就寫了這幾個控件的美化,雖然這破代碼搗鼓好幾天了,但代碼依舊混亂不堪,加上反編譯了微軟的部分東西,由於想盡快出來,代碼都沒看,直接複製過來修改爲編譯不報錯就完事了,spa
如今我來講說我實現的思路:3d
前題條件繼承的是本身寫的FormBase
而後重寫了系統的OnControlAdded 方法,在這裏爲每一個控件添加美化的類,rest
可怎麼添加了? 找了很久,找到了一個可攔截Control消息的接口:IWindowTarget 接口(具體請參考 MSDN 微軟不建議直接使用的一個類)code
Control 公開並容許修改這個接口的信息,orm
IWindowTarget 接口有兩個方法,一個是更換控件句柄的(也許應該叫設置控件句柄) 還有一個就是處理 Windows 消息的OnMessage
我要作的就是攔截Windows 消息的重畫消息,攔截下來 而後本身畫,其它的仍是丟個控件處理,(後來發現貌似實現IMessageFilter接口也能夠實現)blog
好了屁話很少說了 上代碼 上demo 沒寫完 但願大神能幫忙完善下就最好了-.-!繼承
對了 就是問個2B問題,怎麼攔截全部的Form建立或者Form建立句柄時?我用IMessageFilter好像攔截不到,
唉 代碼有點亂,各位將就着看吧
部分代碼:
using DotNet.Windows.Forms.Internal; using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; namespace DotNet.Windows.Forms { public abstract class WindowTarget<T> : IWindowTarget where T : Control { private static readonly ControlStyles UserControlStyles; private static readonly MethodInfo SetStyleMethod; private static readonly MethodInfo SetStateMethod; private static readonly PropertyInfo CacheTextInternalProperty; private static readonly FieldInfo windowField; static WindowTarget() { UserControlStyles = ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.ContainerControl | ControlStyles.UserPaint; SetStyleMethod = typeof(Control).GetMethod("SetStyle",BindingFlags.Instance |BindingFlags.NonPublic); SetStateMethod = typeof(Control).GetMethod("SetState", BindingFlags.Instance | BindingFlags.NonPublic); windowField = typeof(Control).GetField("window", BindingFlags.Instance | BindingFlags.NonPublic); CacheTextInternalProperty = typeof(Control).GetProperty("CacheTextInternal", BindingFlags.Instance | BindingFlags.NonPublic); } private T m_Control; private IWindowTarget m_WindowTarget; private MouseState m_MouseState = MouseState.Normal; protected WindowTarget(T control) { m_Control = control; m_WindowTarget = m_Control.WindowTarget; m_Control.MouseUp += (o, e) => { this.MouseState = MouseState.Up; }; m_Control.MouseEnter += (o, e) => { this.MouseState = MouseState.Move; }; m_Control.MouseLeave += (o, e) => { this.MouseState = MouseState.Leave; }; m_Control.MouseDown += (o, e) => { this.MouseState = MouseState.Down; }; } protected virtual void SetStyle(ControlStyles styles, bool value) { SetStyleMethod.Invoke(Control, new object[] { styles, value }); } private object window { get { return windowField.GetValue(Control); } } private bool CacheTextInternal { get { return (bool)CacheTextInternalProperty.GetValue(Control, null); } set { CacheTextInternalProperty.SetValue(Control, value, null); } } protected virtual void SetState(int flag, bool value) { SetStyleMethod.Invoke(Control, new object[] { flag, value }); } protected T Control { get { return m_Control; } } protected IWindowTarget Target { get { return m_WindowTarget; } } protected abstract void OnPaint(DotNet.Windows.Forms.Internal.PaintEventArgs e); protected MouseState MouseState { get { return m_MouseState; } set { if (m_MouseState != value) { m_MouseState = value; Control.Invalidate(); } } } protected virtual Image GetImage() { switch (MouseState) { case MouseState.Leave: case MouseState.Normal: return GetNormalImage(); case MouseState.Up: case MouseState.Move: return GetMoveImage(); case MouseState.Down: return GetDownImage(); default: return null; } } protected abstract Image GetNormalImage(); protected abstract Image GetMoveImage(); protected abstract Image GetDownImage(); protected void RendererBackground(Graphics g, Rectangle rect, Image backgroundImage, bool method) { if (!method) { g.DrawImage(backgroundImage, new Rectangle(rect.X + 0, rect.Y, 5, rect.Height), 0, 0, 5, backgroundImage.Height, GraphicsUnit.Pixel); g.DrawImage(backgroundImage, new Rectangle(rect.X + 5, rect.Y, rect.Width - 10, rect.Height), 5, 0, backgroundImage.Width - 10, backgroundImage.Height, GraphicsUnit.Pixel); g.DrawImage(backgroundImage, new Rectangle(rect.X + rect.Width - 5, rect.Y, 5, rect.Height), backgroundImage.Width - 5, 0, 5, backgroundImage.Height, GraphicsUnit.Pixel); } else { RendererBackground(g, rect, 5, backgroundImage); } } /// <summary> /// 渲染背景圖片,使背景圖片不失真 /// </summary> /// <param name="g"></param> /// <param name="rect"></param> /// <param name="cut"></param> /// <param name="backgroundImage"></param> protected void RendererBackground(Graphics g, Rectangle rect, int cut, Image backgroundImage) { //左上角 g.DrawImage(backgroundImage, new Rectangle(rect.X, rect.Y, cut, cut), 0, 0, cut, cut, GraphicsUnit.Pixel); //上邊 g.DrawImage(backgroundImage, new Rectangle(rect.X + cut, rect.Y, rect.Width - cut * 2, cut), cut, 0, backgroundImage.Width - cut * 2, cut, GraphicsUnit.Pixel); //右上角 g.DrawImage(backgroundImage, new Rectangle(rect.X + rect.Width - cut, rect.Y, cut, cut), backgroundImage.Width - cut, 0, cut, cut, GraphicsUnit.Pixel); //左邊 g.DrawImage(backgroundImage, new Rectangle(rect.X, rect.Y + cut, cut, rect.Height - cut * 2), 0, cut, cut, backgroundImage.Height - cut * 2, GraphicsUnit.Pixel); //左下角 g.DrawImage(backgroundImage, new Rectangle(rect.X, rect.Y + rect.Height - cut, cut, cut), 0, backgroundImage.Height - cut, cut, cut, GraphicsUnit.Pixel); //右邊 g.DrawImage(backgroundImage, new Rectangle(rect.X + rect.Width - cut, rect.Y + cut, cut, rect.Height - cut * 2), backgroundImage.Width - cut, cut, cut, backgroundImage.Height - cut * 2, GraphicsUnit.Pixel); //右下角 g.DrawImage(backgroundImage, new Rectangle(rect.X + rect.Width - cut, rect.Y + rect.Height - cut, cut, cut), backgroundImage.Width - cut, backgroundImage.Height - cut, cut, cut, GraphicsUnit.Pixel); //下邊 g.DrawImage(backgroundImage, new Rectangle(rect.X + cut, rect.Y + rect.Height - cut, rect.Width - cut * 2, cut), cut, backgroundImage.Height - cut, backgroundImage.Width - cut * 2, cut, GraphicsUnit.Pixel); //平鋪中間 g.DrawImage(backgroundImage, new Rectangle(rect.X + cut, rect.Y + cut, rect.Width - cut * 2, rect.Height - cut * 2), cut, cut, backgroundImage.Width - cut * 2, backgroundImage.Height - cut * 2, GraphicsUnit.Pixel); } #region IWindowTarget 成員 void IWindowTarget.OnHandleChange(IntPtr newHandle) { Target.OnHandleChange(newHandle); } private BufferedGraphicsContext BufferContext { get { return BufferedGraphicsManager.Current; } } internal static IntPtr SetUpPalette(IntPtr dc, bool force, bool realizePalette) { IntPtr halftonePalette = Graphics.GetHalftonePalette(); IntPtr ptr2 = SafeNativeMethods.SelectPalette(new HandleRef(null, dc), new HandleRef(null, halftonePalette), force ? 0 : 1); if ((ptr2 != IntPtr.Zero) && realizePalette) { SafeNativeMethods.RealizePalette(new HandleRef(null, dc)); } return ptr2; } private void WmPaint(ref Message m) { bool flag = true; IntPtr zero = IntPtr.Zero; NativeMethods.PAINTSTRUCT lpPaint = new NativeMethods.PAINTSTRUCT(); bool flag2 = false; try { IntPtr wParam; Rectangle clientRectangle; if (m.WParam == IntPtr.Zero) { zero = Control.Handle; wParam = UnsafeNativeMethods.BeginPaint(new HandleRef(this, zero), ref lpPaint); flag2 = true; clientRectangle = new Rectangle(lpPaint.rcPaint_left, lpPaint.rcPaint_top, lpPaint.rcPaint_right - lpPaint.rcPaint_left, lpPaint.rcPaint_bottom - lpPaint.rcPaint_top); } else { wParam = m.WParam; clientRectangle = Control.ClientRectangle; } if (!flag || ((clientRectangle.Width > 0) && (clientRectangle.Height > 0))) { IntPtr handle = IntPtr.Zero; BufferedGraphics graphics = null; DotNet.Windows.Forms.Internal.PaintEventArgs e = null; System.Drawing.Drawing2D.GraphicsState gstate = null; try { if (flag || (m.WParam == IntPtr.Zero)) { handle = SetUpPalette(wParam, false, false); } if (flag) { try { graphics = this.BufferContext.Allocate(wParam, Control.ClientRectangle); } catch (Exception exception) { if (ClientUtils.IsCriticalException(exception)) { throw; } flag = false; } } if (graphics != null) { graphics.Graphics.SetClip(clientRectangle); e = new DotNet.Windows.Forms.Internal.PaintEventArgs(graphics.Graphics, clientRectangle); gstate = e.Graphics.Save(); } else { e = new DotNet.Windows.Forms.Internal.PaintEventArgs(wParam, clientRectangle); } using (e) { try { if (((m.WParam == IntPtr.Zero) && true) || flag) { this.PaintWithErrorHandling(e, 1); } } finally { if (gstate != null) { e.Graphics.Restore(gstate); } else { e.ResetGraphics(); } } this.PaintWithErrorHandling(e, 2); if (graphics != null) { graphics.Render(); } } } finally { if (handle != IntPtr.Zero) { SafeNativeMethods.SelectPalette(new HandleRef(null, wParam), new HandleRef(null, handle), 0); } if (graphics != null) { graphics.Dispose(); } } } } finally { if (flag2) { UnsafeNativeMethods.EndPaint(new HandleRef(this, zero), ref lpPaint); } } } protected virtual void OnPaintBackground(DotNet.Windows.Forms.Internal.PaintEventArgs pevent) { NativeMethods.RECT rect = new NativeMethods.RECT(); UnsafeNativeMethods.GetClientRect(new HandleRef(this.window, Control.Handle), ref rect); this.PaintBackground(pevent, new Rectangle(rect.left, rect.top, rect.right, rect.bottom)); } internal void PaintBackground(DotNet.Windows.Forms.Internal.PaintEventArgs e, Rectangle rectangle) { this.PaintBackground(e, rectangle, Control.BackColor, Point.Empty); } internal void PaintBackground(DotNet.Windows.Forms.Internal.PaintEventArgs e, Rectangle rectangle, System.Drawing.Color backColor) { this.PaintBackground(e, rectangle, backColor, Point.Empty); } private bool RenderColorTransparent(System.Drawing.Color c) { return ((c.A < 0xff)); } internal void PaintTransparentBackground(DotNet.Windows.Forms.Internal.PaintEventArgs e, Rectangle rectangle) { this.PaintTransparentBackground(e, rectangle, null); } internal static bool IsImageTransparent(Image backgroundImage) { return ((backgroundImage != null) && ((backgroundImage.Flags & 2) > 0)); } internal static Rectangle CalculateBackgroundImageRectangle(Rectangle bounds, Image backgroundImage, ImageLayout imageLayout) { Rectangle rectangle = bounds; if (backgroundImage != null) { switch (imageLayout) { case ImageLayout.None: rectangle.Size = backgroundImage.Size; return rectangle; case ImageLayout.Tile: return rectangle; case ImageLayout.Center: { rectangle.Size = backgroundImage.Size; Size size = bounds.Size; if (size.Width > rectangle.Width) { rectangle.X = (size.Width - rectangle.Width) / 2; } if (size.Height > rectangle.Height) { rectangle.Y = (size.Height - rectangle.Height) / 2; } return rectangle; } case ImageLayout.Stretch: rectangle.Size = bounds.Size; return rectangle; case ImageLayout.Zoom: { Size size2 = backgroundImage.Size; float num = ((float)bounds.Width) / ((float)size2.Width); float num2 = ((float)bounds.Height) / ((float)size2.Height); if (num >= num2) { rectangle.Height = bounds.Height; rectangle.Width = (int)((size2.Width * num2) + 0.5); if (bounds.X >= 0) { rectangle.X = (bounds.Width - rectangle.Width) / 2; } return rectangle; } rectangle.Width = bounds.Width; rectangle.Height = (int)((size2.Height * num) + 0.5); if (bounds.Y >= 0) { rectangle.Y = (bounds.Height - rectangle.Height) / 2; } return rectangle; } } } return rectangle; } internal static void DrawBackgroundImage(Graphics g, Image backgroundImage, Color backColor, ImageLayout backgroundImageLayout, Rectangle bounds, Rectangle clipRect, Point scrollOffset, RightToLeft rightToLeft) { if (g == null) { throw new ArgumentNullException("g"); } if (backgroundImageLayout == ImageLayout.Tile) { using (TextureBrush brush = new TextureBrush(backgroundImage, WrapMode.Tile)) { if (scrollOffset != Point.Empty) { Matrix transform = brush.Transform; transform.Translate((float)scrollOffset.X, (float)scrollOffset.Y); brush.Transform = transform; } g.FillRectangle(brush, clipRect); return; } } Rectangle rect = CalculateBackgroundImageRectangle(bounds, backgroundImage, backgroundImageLayout); if ((rightToLeft == RightToLeft.Yes) && (backgroundImageLayout == ImageLayout.None)) { rect.X += clipRect.Width - rect.Width; } using (SolidBrush brush2 = new SolidBrush(backColor)) { g.FillRectangle(brush2, clipRect); } if (!clipRect.Contains(rect)) { if ((backgroundImageLayout == ImageLayout.Stretch) || (backgroundImageLayout == ImageLayout.Zoom)) { rect.Intersect(clipRect); g.DrawImage(backgroundImage, rect); } else if (backgroundImageLayout == ImageLayout.None) { rect.Offset(clipRect.Location); Rectangle destRect = rect; destRect.Intersect(clipRect); Rectangle rectangle3 = new Rectangle(Point.Empty, destRect.Size); g.DrawImage(backgroundImage, destRect, rectangle3.X, rectangle3.Y, rectangle3.Width, rectangle3.Height, GraphicsUnit.Pixel); } else { Rectangle rectangle4 = rect; rectangle4.Intersect(clipRect); Rectangle rectangle5 = new Rectangle(new Point(rectangle4.X - rect.X, rectangle4.Y - rect.Y), rectangle4.Size); g.DrawImage(backgroundImage, rectangle4, rectangle5.X, rectangle5.Y, rectangle5.Width, rectangle5.Height, GraphicsUnit.Pixel); } } else { ImageAttributes imageAttr = new ImageAttributes(); imageAttr.SetWrapMode(WrapMode.TileFlipXY); g.DrawImage(backgroundImage, rect, 0, 0, backgroundImage.Width, backgroundImage.Height, GraphicsUnit.Pixel, imageAttr); imageAttr.Dispose(); } } internal void PaintTransparentBackground(DotNet.Windows.Forms.Internal.PaintEventArgs e, Rectangle rectangle, System.Drawing.Region transparentRegion) { Graphics g = e.Graphics; Control parentInternal = Control.Parent; if (parentInternal != null) { if (Application.RenderWithVisualStyles) // parentInternal.RenderTransparencyWithVisualStyles) { System.Drawing.Drawing2D.GraphicsState gstate = null; if (transparentRegion != null) { gstate = g.Save(); } try { if (transparentRegion != null) { g.Clip = transparentRegion; } ButtonRenderer.DrawParentBackground(g, rectangle, Control); return; } finally { if (gstate != null) { g.Restore(gstate); } } } Rectangle rectangle2 = new Rectangle(-Control.Left, -Control.Top, parentInternal.Width, parentInternal.Height); Rectangle clipRect = new Rectangle(rectangle.Left + Control.Left, rectangle.Top + Control.Top, rectangle.Width, rectangle.Height); using (WindowsGraphics graphics2 = WindowsGraphics.FromGraphics(g)) { graphics2.DeviceContext.TranslateTransform(-Control.Left, -Control.Top); using (DotNet.Windows.Forms.Internal.PaintEventArgs args = new DotNet.Windows.Forms.Internal.PaintEventArgs(graphics2.GetHdc(), clipRect)) { if (transparentRegion != null) { args.Graphics.Clip = transparentRegion; args.Graphics.TranslateClip(-rectangle2.X, -rectangle2.Y); } try { //this.InvokePaintBackground(parentInternal, args); //this.InvokePaint(parentInternal, args); } finally { if (transparentRegion != null) { args.Graphics.TranslateClip(rectangle2.X, rectangle2.Y); } } } return; } } g.FillRectangle(SystemBrushes.Control, rectangle); } internal void PaintBackground(DotNet.Windows.Forms.Internal.PaintEventArgs e, Rectangle rectangle, System.Drawing.Color backColor, Point scrollOffset) { backColor = Color.Transparent; //ControlStyles.SupportsTransparentBackColor; this.PaintTransparentBackground(e, rectangle); //if (this.RenderColorTransparent(backColor)) //{ // this.PaintTransparentBackground(e, rectangle); //} bool flag = ((Control is FormBase) || (this is MdiClient)) && Control.IsMirrored; if (((Control.BackgroundImage != null) && !SystemInformation.HighContrast) && !flag) { if ((Control.BackgroundImageLayout == ImageLayout.Tile) && IsImageTransparent(Control.BackgroundImage)) { PaintTransparentBackground(e, rectangle); } Point autoScrollPosition = scrollOffset; if ((Control is ScrollableControl) && (autoScrollPosition != Point.Empty)) { autoScrollPosition = ((ScrollableControl)(Control)Control).AutoScrollPosition; } if (IsImageTransparent(Control.BackgroundImage)) { PaintBackColor(e, rectangle, backColor); } DrawBackgroundImage(e.Graphics, Control.BackgroundImage, backColor, Control.BackgroundImageLayout, Control.ClientRectangle, rectangle, autoScrollPosition, Control.RightToLeft); } else { PaintBackColor(e, rectangle, backColor); } } private static void PaintBackColor(DotNet.Windows.Forms.Internal.PaintEventArgs e, Rectangle rectangle, System.Drawing.Color backColor) { System.Drawing.Color nearestColor = backColor; if (nearestColor.A == 0xff) { using (WindowsGraphics graphics = ((e.HDC != IntPtr.Zero) && ((short)Screen.PrimaryScreen.BitsPerPixel > 8)) ? WindowsGraphics.FromHdc(e.HDC) : WindowsGraphics.FromGraphics(e.Graphics)) { nearestColor = graphics.GetNearestColor(nearestColor); using (WindowsBrush brush = new WindowsSolidBrush(graphics.DeviceContext, nearestColor)) { graphics.FillRectangle(brush, rectangle); } return; } } if (nearestColor.A > 0) { using (Brush brush2 = new SolidBrush(nearestColor)) { e.Graphics.FillRectangle(brush2, rectangle); } } } private void PaintWithErrorHandling(DotNet.Windows.Forms.Internal.PaintEventArgs e, short layer) { try { this.CacheTextInternal = true; bool flag = true; try { switch (layer) { case 1: this.OnPaintBackground(e); break; case 2: this.OnPaint(e); break; } flag = false; } finally { if (flag) { this.SetState(0x400000, true); Control.Invalidate(); } } } finally { this.CacheTextInternal = false; } } void IWindowTarget.OnMessage(ref Message m) { if (m.Msg == 15) { WmPaint(ref m); return; } Target.OnMessage(ref m); } #endregion } }
http://files.cnblogs.com/dotnet-org-cn/DotNet.Framework.rar
最後打個小廣告:中國.NET協會(http://www.dotnet.org.cn)
騰訊企鵝羣:45132984
博客園地址:http://http://www.cnblogs.com/dotnet-org-cn 國內惟一一個以非盈利的.NET協會,致力打造國內具備權威性、價值性的.NET協會。