WinForms形成皮肤

介绍 SkinForm类允许您创建自定义皮肤。net WinForms表单对象,对象多达你想补充道,并处理许多事件(如鼠标、键盘和油漆)对你的皮肤像你使用标准的控制。 背景 很多WinForms应用程序有自己的皮肤有更好的外观和感觉与标准相比WinForms的皮肤。也少的WinForms应用程序有用我们的应用程序中,这是地方放置表单的文本和系统按钮(在我的环境中,我称之为酒吧形式)。此外,改善我们的外观和感觉,更好地利用屏幕的面积可以给我们一个特殊的点。所以,我们为什么不尝试创建更好的自己吗? 预览 自定义皮肤(AiSkin): 自定义皮肤(AiSkin)额外的自定义按钮放置在系统按钮: 自定义皮肤(AiSkin)额外的自定义按钮放置在系统按钮,和选项卡: 主要的对象 有几类皮肤(在Ai。控制命名空间): 主要课程: SkinForm类。 这是主要的类来管理皮肤和皮肤之间的联系形式。 FormHook类。 从NativeWindow继承类。定意把消息处理通过指向剥皮的形式。这个类包含在SkinForm类。 SkinBase类。 基类皮肤管理。这个类包含皮肤的变量信息,被FormHook类和函数来处理消息。 BarFormButton类。 类代表一个按钮将被放置在酒吧的形式。 MinimizeButton类。 继承自BarFormButton,代表了最小化按钮的形式。 MaximizeButton类。 继承自BarFormButton,表示表单的最大化按钮。 CloseButton类。 继承BarFormButton,代表了关闭按钮的形式。 其他类: CustomButton类。 继承自BarFormButton,代表了一个自定义按钮的形式。 TabFormButton类。 类代表一个选项卡按钮,将放在吧台形式。BarFormButtonCollection类。 代表BarFormButton对象的集合。这个集合不能包含MinimizeButton之一,MaximizeButton或CloseButton。 TabFormButtonCollection类。 代表TabFormButton对象的集合。 Win32API类。 封装结构、外部函数和常量用于win32 API调用。 示例类: AiSkin类。 SkinBase的实现类,支持标签和自定义按钮。 创建和使用自己的自定义皮肤,创建一个类,继承SkinBase类,创建一个SkinForm类的实例并定制皮肤类在WinForms表单对象,并设置形式和皮肤SkinForm实例的属性的实例WinForms形式和定制皮肤的实例,如下: 隐藏,复制Code

public class YourSkin : SkinBase
{
	// your implementation here
}

public class YourForm : System.Windows.Forms.Form
{
	public YourForm()
	{
		// Create an instance of SkinForm class.
		SkinForm sf = new SkinForm();
		// Create an instance of YourSkin class.
		YourSkin skin = new YourSkin();
		// Sets both Form and Skin property of sf.
		sf.Skin = skin;
		sf.Form = this;
	}
}

简要描述 以下是简短的解释重要的事情来开发定制的皮肤。 FormHook 这个类的目的是把剥了皮的窗口消息处理形式通过其指向功能。这个类将提供皮肤所需的任何事件的过程。对于键盘消息处理,这类使用windows原始输入功能。剥了皮的形式将注册接收原始表单的输入消息HandleCreated事件时触发。 隐藏,复制Code

private class FormHook : NativeWindow
{
	// ...
	/// <summary>
	/// Called when the handle of the form is created.
	/// </summary>
	private void form_HandleCreated(object sender, EventArgs e)
	{
		AssignHandle(((Form)sender).Handle);
		// Registering form for raw input
		Win32API.RAWINPUTDEVICE[] rid = new Win32API.RAWINPUTDEVICE[1];
		rid[0].usUsagePage = 0x01;
		rid[0].usUsage = 0x06;
		rid[0].dwFlags = Win32API.RIDEV_INPUTSINK;
		rid[0].hwndTarget = ((Form)sender).Handle;
		_RIDRegistered = Win32API.RegisterRawInputDevices
                        (rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));
		if (isProcessNCArea()) 
		{
			updateStyle();
			updateCaption();
		}
	}
}

窗口消息连接过程发生在指向这个类的函数。 隐藏,收缩,复制Code

private class FormHook : NativeWindow
{
	// ...

	/// <summary>
	/// Invokes the default window procedure associated with this window.
	/// </summary>
	[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
	protected override void WndProc(ref Message m) {
		bool suppressOriginalMessage = false;
		switch (m.Msg) { 
			case Win32API.WM_STYLECHANGED:
				updateStyle();
				if (_owner._skin != null) _owner._skin.setRegion(_owner._form.Size);
				break;
			#region Form Activation
			case Win32API.WM_ACTIVATEAPP:
				if (_owner._skin != null) _owner._skin.FormIsActive = (int)m.WParam != 0;
				onNCPaint(true);
				break;
			case Win32API.WM_ACTIVATE:
				if (_owner._skin != null) _owner._skin.FormIsActive = 
                         ((int)Win32API.WA_ACTIVE == (int)m.WParam || 
                                 (int)Win32API.WA_CLICKACTIVE == (int)m.WParam);
				onNCPaint(true);
				break;
			case Win32API.WM_MDIACTIVATE:
				if (m.WParam == _owner._form.Handle) {
					if (_owner._skin != null) _owner._skin.FormIsActive = false;
				} else if (m.LParam == _owner._form.Handle) {
					if (_owner._skin != null) _owner._skin.FormIsActive = true;
				}
				onNCPaint(true);
				break;
			#endregion
			#region Mouse Events
			case Win32API.WM_NCLBUTTONDOWN:
			case Win32API.WM_NCRBUTTONDOWN:
			case Win32API.WM_NCMBUTTONDOWN:
				suppressOriginalMessage = onNCMouseDown(ref m);
				break;
			case Win32API.WM_NCLBUTTONUP:
			case Win32API.WM_NCMBUTTONUP:
			case Win32API.WM_NCRBUTTONUP:
				suppressOriginalMessage = onNCMouseUp(ref m);
				break;
			case Win32API.WM_NCMOUSEMOVE:
				suppressOriginalMessage = onNCMouseMove(ref m);
				break;
			case Win32API.WM_NCMOUSELEAVE:
			case Win32API.WM_MOUSELEAVE:
			case Win32API.WM_MOUSEHOVER:
				_owner._skin.onMouseLeave();
				break;
			case Win32API.WM_NCLBUTTONDBLCLK:
				suppressOriginalMessage = onNCDoubleClick(ref m);
				break;
			#endregion
			#region Non-client Hit Test
			case Win32API.WM_NCHITTEST:
				suppressOriginalMessage = onNCHitTest(ref m);
				break;
			#endregion
			#region Painting and sizing operation
			case Win32API.WM_NCPAINT:
				if (onNCPaint(true)) {
					m.Result = (IntPtr)1;
					suppressOriginalMessage = true;
				}
				break;
			case Win32API.WM_NCCALCSIZE:
				if (m.WParam == (IntPtr)1) {
					if (!isProcessNCArea()) break;
					Win32API.NCCALCSIZE_PARAMS p = (Win32API.NCCALCSIZE_PARAMS)m.GetLParam
                                                   (typeof(Win32API.NCCALCSIZE_PARAMS));
					if (_owner._skin != null) p = _owner._skin.calculateNonClient(p);
					Marshal.StructureToPtr(p, m.LParam, true);
					suppressOriginalMessage = true;
				}
				break;
			case Win32API.WM_SHOWWINDOW:
				if (_owner._skin != null) _owner._skin.setRegion(_owner._form.Size);
				break;
			case Win32API.WM_SIZE:
				onResize(m);
				break;
			case Win32API.WM_GETMINMAXINFO:
				suppressOriginalMessage = calculateMaximumSize(ref m);
				break;
			case Win32API.WM_WINDOWPOSCHANGING:
				Win32API.WINDOWPOS wndPos = (Win32API.WINDOWPOS)m.GetLParam
                                            (typeof(Win32API.WINDOWPOS));
				if ((wndPos.flags & Win32API.SWP_NOSIZE) == 0) {
					if (_owner._skin != null) _owner._skin.setRegion
                                        (new Size(wndPos.cx, wndPos.cy));
				}
				break;
			case Win32API.WM_WINDOWPOSCHANGED:
				if (_owner._form.WindowState == FormWindowState.Maximized) 
                                                     _owner._form.Region = null;
				Win32API.WINDOWPOS wndPos2 = (Win32API.WINDOWPOS)m.GetLParam
                                                     (typeof(Win32API.WINDOWPOS));
				if ((wndPos2.flags & (int)Win32API.SWP_NOSIZE) == 0) {
					updateCaption();
					onNCPaint(true);
				}
				break;
			#endregion
			#region Raw Input
			case Win32API.WM_INPUT:
				if (_owner._skin != null) {
					if (_owner._skin.FormIsActive) {
						uint dwSize = 0, receivedBytes;
						uint szRIHeader = 
                           (uint)Marshal.SizeOf(typeof(Win32API.RAWINPUTHEADER));
						int res = Win32API.GetRawInputData(m.LParam, 
                                  Win32API.RID_INPUT, IntPtr.Zero, ref dwSize, szRIHeader);
						if (res == 0) {
							IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);
							if (buffer != IntPtr.Zero) {
								receivedBytes = (uint)Win32API.GetRawInputData
                                (m.LParam, Win32API.RID_INPUT, buffer, ref dwSize, szRIHeader);
								Win32API.RAWINPUT raw = (Win32API.RAWINPUT)
                                Marshal.PtrToStructure(buffer, typeof(Win32API.RAWINPUT));
								if (raw.header.dwType == Win32API.RIM_TYPEKEYBOARD) {
									// Process keyboard event.
									if (raw.keyboard.Message == Win32API.WM_KEYDOWN || 
                                        raw.keyboard.Message == Win32API.WM_SYSKEYDOWN) {
										ushort key = raw.keyboard.VKey;
										Keys kd = (Keys)Enum.Parse(typeof(Keys), 
                                                  Enum.GetName(typeof(Keys), key));
										if (kd != System.Windows.Forms.Control.ModifierKeys) 
                                        kd = kd | System.Windows.Forms.Control.ModifierKeys;
										// Call skin's onKeyDown function.
										KeyEventArgs ke = new KeyEventArgs(kd);
										suppressOriginalMessage = _owner._skin.onKeyDown(ke);
									}
								}
							}
						}
					}
				}
				break;
			#endregion
		}
		if(!suppressOriginalMessage) base.WndProc(ref m);
	}
}

SkinBase 这个类封装了基本组件和功能需要构建自己的皮肤。 3系统的基本组件包括按钮(最小化、最大化、关闭),矩形对持有非客户区信息。 隐藏,复制Code

public abstract class SkinBase : IDisposable {
	// ...
	#region Protected Fields
	protected MinimizeButton _minimizeButton = new MinimizeButton();
	protected MaximizeButton _maximizeButton = new MaximizeButton();
	protected CloseButton _closeButton = new CloseButton();
	protected bool _formIsActive = true;
	#region Standard Rectangle for Non-client area
	protected Rectangle _rectClient;
	protected Rectangle _rectIcon;
	protected internal Rectangle _rectBar;
	protected Rectangle _rectBorderTop;
	protected internal Rectangle _rectBorderLeft;
	protected internal Rectangle _rectBorderBottom;
	protected internal Rectangle _rectBorderRight;
	protected Rectangle _rectBorderTopLeft;
	protected Rectangle _rectBorderTopRight;
	protected Rectangle _rectBorderBottomLeft;
	protected Rectangle _rectBorderBottomRight;
	#endregion
	#endregion
}

基本功能对皮肤形成消息处理,封面激活/失活,碰撞测试,形成大小/状态改变/文本变化,非客户区鼠标事件(鼠标,鼠标,下双击),和按键按下。鼠标事件和碰撞测试,鼠标指针的位置是相对于表单的左上角,而不是屏幕。 隐藏,收缩,复制Code

public abstract class SkinBase : IDisposable {
	// ...
	/// <summary>
	/// Called when the text property of the form has been changed.
	/// </summary>
	protected internal abstract void onFormTextChanged();
	/// <summary>
	/// Called when the left button of the mouse is double-clicked on the 
    /// non-client area of the form.
	/// </summary>
	protected internal abstract bool onDoubleClick();
	/// <summary>
	/// Called when the mouse pointer is moved over the non-client area of the form.
	/// </summary>
	protected internal abstract bool onMouseMove(MouseEventArgs e);
	/// <summary>
	/// Called when the mouse pointer is over the non-client area of the form 
    /// and a mouse button is pressed.
	/// </summary>
	protected internal abstract bool onMouseDown(MouseEventArgs e);
	/// <summary>
	/// Called when the mouse pointer is over the non-client area of the form 
    /// and a mouse button is released.
	/// </summary>
	protected internal abstract bool onMouseUp(MouseEventArgs e);
	/// <summary>
	/// Called when the mouse pointer is leaving the non-client area of the form.
	/// </summary>
	protected internal abstract bool onMouseLeave();
	/// <summary>
	/// Called when the non-client area of the form is redrawn
	/// </summary>
	protected internal abstract bool onPaint(PaintEventArgs e);
	/// <summary>
	/// Called when one of the registered keys of the skin is pressed.
	/// </summary>
	protected internal abstract bool onKeyDown(KeyEventArgs e);
	/// <summary>
	/// Called when the form need to set its region.
	/// </summary>
	protected internal abstract bool setRegion(Size size);
	/// <summary>
	/// Called when the non-client are of the form need to be calculated.
	/// </summary>
	protected internal abstract Win32API.NCCALCSIZE_PARAMS 
                       calculateNonClient(Win32API.NCCALCSIZE_PARAMS p);
	/// <summary>
	/// Called when the bar of the form is updated.
	/// </summary>
	protected internal abstract void updateBar(Rectangle rect);
	/// <summary>
	/// Called when the hit-test is performed on the non-client area of the form.
	/// </summary>
	protected internal abstract int nonClientHitTest(Point p);
}

在创建定制皮肤通过继承SkinBase类时,重要的事情我们需要注意calculateNonClient和nonClientHitTest功能。 calculateNonClient函数是函数,你必须决定的大小非客户区域的形式通过修改p。rect0值: 减少p.rect0的价值。你领域的高度酒吧形式。减少p.rect0的价值。离开字段的表单的左边框的宽度。减少p.rect0的价值。正确的字段的表单的右边框的宽度。减少p.rect0的价值。底部高度字段的表单的底部边框。 Hide,收缩,复制Code

protected internal override Win32API.NCCALCSIZE_PARAMS calculateNonClient
     (Win32API.NCCALCSIZE_PARAMS p) {
	// Check if we don't need to calculate the client area.
	if (Form == null || Form.WindowState == FormWindowState.Minimized || 
		(Form.WindowState == FormWindowState.Minimized && Form.MdiParent != null)) return p;
	// Calculate the valid client area of the form here, that is stored 
    // in rect0 of the p parameter.
	p.rect0.Top += _rectBar.Height;
	_rectClient.Y = _rectBar.Height + 1;
	if (Form.WindowState == FormWindowState.Maximized) { 
		// The form is maximized, thus the borders will not be calculated 
        // and the status bar only will be calculated.
		//p.rect0.Bottom -= _rectStatus.Height;
		_rectClient.X = 0;
		_rectClient.Width = p.rect0.Right - (p.rect0.Left + 1);
		_rectClient.Height = p.rect0.Bottom - (p.rect0.Top + 1);
	} else { 
		// Deflate the left, right, and bottom of the rect0 by the left border width,
		// right border width, and sum of the status and bottom border height.
		p.rect0.Left += _rectBorderLeft.Width;
		p.rect0.Right -= _rectBorderRight.Width;
		p.rect0.Bottom -= _rectBorderBottom.Height;
		_rectClient.X = _rectBorderLeft.Width + 1;
		_rectClient.Width = p.rect0.Right - (p.rect0.Left + 2);
		_rectClient.Height = p.rect0.Bottom - (p.rect0.Top + 2);
	}
	return p;
}

nonClientHitTest函数是告诉系统鼠标指针指向了非客户区的哪一部分。传递给此函数的Point p参数相对于已蒙皮表单的左上角。此函数的结果必须是hit-test结果常量之一,这些常量前缀为HT。在我的实现中,当鼠标指针指向最小化、最大化或关闭按钮时,我返回HTOBJECT,而不是返回HTMINBUTTON、HTMAXBUTTON或HTCLOSE,因为我宁愿使用自己的工具提示,而不是系统工具提示:D。 隐藏,收缩,复制Code

protected internal override int nonClientHitTest(Point p) {
	if (_rectClient.Contains(p)) return Win32API.HTCLIENT;
	if (_rectIcon.Contains(p)) return Win32API.HTMENU;
	// Always return HTOBJECT instead of the corresponding hittest value, 
    // to prevent the default tooltip to be shown.
	if (_minimizeButton.Enabled && _minimizeButton.Visible) {
		if (_minHost.Bounds.Contains(p)) return Win32API.HTOBJECT;
	}
	if (_maximizeButton.Enabled && _maximizeButton.Visible) {
		if (_maxHost.Bounds.Contains(p)) return Win32API.HTOBJECT;
	}
	if (_closeButton.Enabled && _closeButton.Visible) {
		if (_closeHost.Bounds.Contains(p)) return Win32API.HTOBJECT;
	}
	// Test for custom bar button, if any of them, then return the HTOBJECT
	if (Form.FormBorderStyle == FormBorderStyle.Sizable || 
        Form.FormBorderStyle == FormBorderStyle.SizableToolWindow 
		&& Form.WindowState != FormWindowState.Maximized) { 
		// Test for borders.
		// Corners
		if (_rectBorderTopLeft.Contains(p)) return Win32API.HTTOPLEFT;
		if (_rectBorderTopRight.Contains(p)) return Win32API.HTTOPRIGHT;
		if (_rectBorderBottomLeft.Contains(p)) return Win32API.HTBOTTOMLEFT;
		if (_rectBorderBottomRight.Contains(p)) return Win32API.HTBOTTOMRIGHT;
		// vertical and horizontal
		if (_rectBorderTop.Contains(p)) return Win32API.HTTOP;
		if (_rectBorderLeft.Contains(p)) return Win32API.HTLEFT;
		if (_rectBorderRight.Contains(p)) return Win32API.HTRIGHT;
		if (_rectBorderBottom.Contains(p)) return Win32API.HTBOTTOM;
	}
	if (Form.WindowState != FormWindowState.Maximized) {
		// Test for bar form.
		if (_rectBar.Contains(p)) return Win32API.HTCAPTION;
	}
	// Default return value.
	return Win32API.HTNOWHERE;
}

历史 2012年7月4日:初版 本文转载于:http://www.diyabc.com/frontweb/news12034.html

原文地址:https://www.cnblogs.com/Dincat/p/13473480.html