好久没来博客园,今天捣鼓到现在就是为了把之前的皮肤控件完善好,
之前也看了很多技术文章,大多数都是自己重写系统控件实现换肤,几乎没有像东日的(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 + , rect.Y, , rect.Height), , , , backgroundImage.Height, GraphicsUnit.Pixel);
g.DrawImage(backgroundImage, new Rectangle(rect.X + , rect.Y, rect.Width - , rect.Height), , , backgroundImage.Width - , backgroundImage.Height, GraphicsUnit.Pixel);
g.DrawImage(backgroundImage, new Rectangle(rect.X + rect.Width - , rect.Y, , rect.Height), backgroundImage.Width - , , , backgroundImage.Height, GraphicsUnit.Pixel);
}
else
{
RendererBackground(g, rect, , 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), , , cut, cut, GraphicsUnit.Pixel);
//上边
g.DrawImage(backgroundImage, new Rectangle(rect.X + cut, rect.Y, rect.Width - cut * , cut), cut, , backgroundImage.Width - cut * , cut, GraphicsUnit.Pixel);
//右上角
g.DrawImage(backgroundImage, new Rectangle(rect.X + rect.Width - cut, rect.Y, cut, cut), backgroundImage.Width - cut, , cut, cut, GraphicsUnit.Pixel);
//左边
g.DrawImage(backgroundImage, new Rectangle(rect.X, rect.Y + cut, cut, rect.Height - cut * ), , cut, cut, backgroundImage.Height - cut * , GraphicsUnit.Pixel);
//左下角
g.DrawImage(backgroundImage, new Rectangle(rect.X, rect.Y + rect.Height - cut, cut, cut), , backgroundImage.Height - cut, cut, cut, GraphicsUnit.Pixel);
//右边
g.DrawImage(backgroundImage, new Rectangle(rect.X + rect.Width - cut, rect.Y + cut, cut, rect.Height - cut * ), backgroundImage.Width - cut, cut, cut, backgroundImage.Height - cut * , 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 * , cut), cut, backgroundImage.Height - cut, backgroundImage.Width - cut * , cut, GraphicsUnit.Pixel);
//平铺中间
g.DrawImage(backgroundImage, new Rectangle(rect.X + cut, rect.Y + cut, rect.Width - cut * , rect.Height - cut * ), cut, cut, backgroundImage.Width - cut * , backgroundImage.Height - cut * , 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 ? : );
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 > ) && (clientRectangle.Height > )))
{
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, );
}
}
finally
{
if (gstate != null)
{
e.Graphics.Restore(gstate);
}
else
{
e.ResetGraphics();
}
}
this.PaintWithErrorHandling(e, );
if (graphics != null)
{
graphics.Render();
}
}
}
finally
{
if (handle != IntPtr.Zero)
{
SafeNativeMethods.SelectPalette(new HandleRef(null, wParam), new HandleRef(null, handle), );
}
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 & ) > ));
}
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) / ;
}
if (size.Height > rectangle.Height)
{
rectangle.Y = (size.Height - rectangle.Height) / ;
}
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 >= )
{
rectangle.X = (bounds.Width - rectangle.Width) / ;
}
return rectangle;
}
rectangle.Width = bounds.Width;
rectangle.Height = (int)((size2.Height * num) + 0.5);
if (bounds.Y >= )
{
rectangle.Y = (bounds.Height - rectangle.Height) / ;
}
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, , , 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 > )) ? 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 > )
{
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 :
this.OnPaintBackground(e);
break;
case :
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 == )
{
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协会。