自己画WinForm 皮肤包括默认控件
好久没来博客园,今天捣鼓到现在就是为了把之前的皮肤控件完善好,
之前也看了很多技术文章,大多数都是自己重写系统控件实现换肤,几乎没有像东日的(IrisSkin)控件一样 添加一个组件 把系统的皮肤全换掉,我曾经也是重写系统的控件,但我就喜欢瞎捣鼓,于是就开始找这方面的资料,苦于没学过底层,对windows窗口 以及消息循环机制不了解,找资料也基本上白搭了许久,但最后以为自己能想到的最笨的方法实现 了继承了自己写的父窗口,那么窗口添加的控件就是自己画的 而不是系统画的,
先上传一张效果图:
整天效果应该也还算勉强吧,目前我也就写了这几个控件的美化,虽然这破代码捣鼓好几天了,但代码依旧混乱不堪,加上反编译了微软的部分东西,因为想尽快出来,代码都没看,直接复制过来修改成编译不报错就完事了,
现在我来说说我实现的思路:
前题条件继承的是自己写的FormBase
然后重写了系统的OnControlAdded 方法,在这里为每个控件添加美化的类,
可怎么添加了? 找了好久,找到了一个可拦截Control消息的接口:IWindowTarget 接口(具体请参考 MSDN 微软不建议直接使用的一个类)
Control 公开并允许修改这个接口的信息,
IWindowTarget 接口有两个方法,一个是更换控件句柄的(也许应该叫设置控件句柄) 还有一个就是处理 Windows 消息的OnMessage
我要做的就是拦截Windows 消息的重画消息,拦截下来 然后自己画,其它的还是丢个控件处理,(后来发现貌似实现IMessageFilter接口也可以实现)
好了屁话不多说了 上代码 上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 } }
https://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协会。
腾讯企鹅群:45132984
博客园地址:http://http://www.cnblogs.com/dotnet-org-cn
国内唯一一个以非盈利的.NET协会,致力打造国内具有权威性、价值性的.NET协会。