前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
<https://gitee.com/kwwwvagaa/net_winform_custom_control>

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492  <https://shang.qq.com/wpa/qunwpa?
idkey=6e08741ef16fe53bf0314c1c9e336c4f626047943a8b76bac062361bab6b4f8d>

目录

https://www.cnblogs.com/bfyx/p/11364884.html
<https://www.cnblogs.com/bfyx/p/11364884.html>

准备工作

这是一个可停靠在指定位置或停靠在某个控件旁边的无焦点窗体,市区焦点会关闭

开始

添加一个Form,命名为FrmAnchor,实现接口IMessageFilter

有2个构造函数
1 #region 构造函数 2 /// <summary> 3 /// 功能描述:构造函数 4 /// 作  者:HZH 5 ///
创建日期:2019-02-27 11:49:08 6 /// 任务编号:POS 7 /// </summary> 8 /// <param
name="parentControl">父控件</param> 9 /// <param name="childControl">子控件</param>
10 /// <param name="deviation">偏移</param> 11 public FrmAnchor(Control
parentControl, Control childControl, Point? deviation =null) 12 { 13
m_parentControl = parentControl; 14 InitializeComponent(); 15 this.Size =
childControl.Size;16 this.HandleCreated += FrmDownBoard_HandleCreated; 17 this
.HandleDestroyed += FrmDownBoard_HandleDestroyed; 18 this
.Controls.Add(childControl);19 childControl.Dock = DockStyle.Fill; 20 Point p =
parentControl.Parent.PointToScreen(parentControl.Location);21 int intX = 0; 22
int intY = 0; 23 if (p.Y + parentControl.Height + childControl.Height >
Screen.PrimaryScreen.Bounds.Height)24 { 25 intY = p.Y - childControl.Height - 1
;26 blnDown = false; 27 } 28 else 29 { 30 intY = p.Y + parentControl.Height +
1; 31 blnDown = true; 32 } 33 34 if (p.X + childControl.Width >
Screen.PrimaryScreen.Bounds.Width)35 { 36 intX =
Screen.PrimaryScreen.Bounds.Width - childControl.Width; 37 38 } 39 else 40 {
41 intX = p.X; 42 } 43 if (deviation.HasValue) 44 { 45 intX +=
deviation.Value.X;46 intY += deviation.Value.Y; 47 } 48 this.Location = new
Point(intX, intY);49 } 50 51 public FrmAnchor(Control parentControl, Size
size, Point? deviation =null) 52 { 53 m_parentControl = parentControl; 54
InitializeComponent();55 this.Size = size; 56 this.HandleCreated +=
FrmDownBoard_HandleCreated;57 this.HandleDestroyed +=
FrmDownBoard_HandleDestroyed;58 59 Point p =
parentControl.Parent.PointToScreen(parentControl.Location);60 int intX = 0; 61
int intY = 0; 62 if (p.Y + parentControl.Height + size.Height >
Screen.PrimaryScreen.Bounds.Height)63 { 64 intY = p.Y - size.Height - 1; 65
blnDown =false; 66 } 67 else 68 { 69 intY = p.Y + parentControl.Height + 1; 70
blnDown =true; 71 } 72 73 if (p.X + size.Width >
Screen.PrimaryScreen.Bounds.Width)74 { 75 intX =
Screen.PrimaryScreen.Bounds.Width - size.Width; 76 77 } 78 else 79 { 80 intX =
p.X;81 } 82 if (deviation.HasValue) 83 { 84 intX += deviation.Value.X; 85
intY += deviation.Value.Y; 86 } 87 this.Location = new Point(intX, intY); 88 }
89 90 #endregion
消息筛选器处理一下
private void FrmDownBoard_HandleDestroyed(object sender, EventArgs e) {
Application.RemoveMessageFilter(this); } private void
FrmDownBoard_HandleCreated(object sender, EventArgs e) {
Application.AddMessageFilter(this); } public bool PreFilterMessage(ref Message
m) {if (m.Msg != 0x0201 || this.Visible == false) return false; var pt = this
.PointToClient(MousePosition);this.Visible = this.ClientRectangle.Contains(pt);
return false; }
无焦点处理
1 #region 无焦点窗体 2 3 [System.Runtime.InteropServices.DllImport("user32.dll")]
4 private extern static IntPtr SetActiveWindow(IntPtr handle); 5 private const
int WM_ACTIVATE = 0x006; 6 private const int WM_ACTIVATEAPP = 0x01C; 7 private
const int WM_NCACTIVATE = 0x086; 8 private const int WA_INACTIVE = 0; 9
private const int WM_MOUSEACTIVATE = 0x21; 10 private const int MA_NOACTIVATE =
3; 11 protected override void WndProc(ref Message m) 12 { 13 if (m.Msg ==
WM_MOUSEACTIVATE)14 { 15 m.Result = new IntPtr(MA_NOACTIVATE); 16 return; 17 }
18 else if (m.Msg == WM_NCACTIVATE) 19 { 20 if (((int)m.WParam & 0xFFFF) !=
WA_INACTIVE)21 { 22 if (m.LParam != IntPtr.Zero) 23 { 24
SetActiveWindow(m.LParam);25 } 26 else 27 { 28 SetActiveWindow(IntPtr.Zero);
29 } 30 } 31 } 32 base.WndProc(ref m); 33 } 34 35 #endregion 1 private void
timer1_Tick(object sender, EventArgs e) 2 { 3 if (this.Owner != null) 4 {
5 Form frm = this.Owner as Form; 6 IntPtr _ptr =
ControlHelper.GetForegroundWindow(); 7 if (_ptr != frm.Handle) 8 { 9 this
.Hide();10 } 11 } 12 }
显示和关闭动画
1 private void FrmAnchor_VisibleChanged(object sender, EventArgs e) 2 { 3
timer1.Enabled =this.Visible; 4 if (Visible) 5 { 6 if (blnDown) 7
ControlHelper.AnimateWindow(this.Handle, 100, ControlHelper.AW_VER_POSITIVE); 8
else 9 { 10 ControlHelper.AnimateWindow(this.Handle, 100,
ControlHelper.AW_VER_NEGATIVE);11 } 12 } 13 else 14 { 15 if (blnDown) 16
ControlHelper.AnimateWindow(this.Handle, 100, ControlHelper.AW_VER_NEGATIVE |
ControlHelper.AW_HIDE);17 else 18 { 19 ControlHelper.AnimateWindow(this.Handle,
100, ControlHelper.AW_VER_POSITIVE | ControlHelper.AW_HIDE); 20 21 } 22 } 23 }
再看一下完整代码
1 // 版权所有 黄正辉 交流群:568015492 QQ:623128629 2 // 文件名称:FrmAnchor.cs 3 //
创建日期:2019-08-15 16:04:24 4 // 功能描述:FrmAnchor 5 // 项目地址:
https://gitee.com/kwwwvagaa/net_winform_custom_control 6 7 using System; 8
using System.Collections.Generic; 9 using System.ComponentModel; 10 using
System.Data; 11 using System.Drawing; 12 using System.Linq; 13 using
System.Text; 14 using System.Windows.Forms; 15 16 namespace HZH_Controls.Forms
17 { 18 /// <summary> 19 /// 功能描述:停靠窗体 20 /// 作  者:HZH 21 ///
创建日期:2019-02-27 11:49:03 22 /// 任务编号:POS 23 /// </summary> 24 public partial
class FrmAnchor : Form, IMessageFilter 25 { 26 Control m_parentControl = null
; 27 private bool blnDown = true; 28 #region 构造函数 29 /// <summary> 30 ///
功能描述:构造函数 31 /// 作  者:HZH 32 /// 创建日期:2019-02-27 11:49:08 33 /// 任务编号:POS 34
/// </summary> 35 /// <param name="parentControl">父控件</param> 36 /// <param
name="childControl">子控件</param> 37 /// <param name="deviation">偏移</param> 38
public FrmAnchor(Control parentControl, Control childControl, Point? deviation =
null) 39 { 40 m_parentControl = parentControl; 41 InitializeComponent();
42 this.Size = childControl.Size; 43 this.HandleCreated +=
FrmDownBoard_HandleCreated; 44 this.HandleDestroyed +=
FrmDownBoard_HandleDestroyed; 45 this.Controls.Add(childControl); 46
childControl.Dock = DockStyle.Fill; 47 Point p =
parentControl.Parent.PointToScreen(parentControl.Location); 48 int intX = 0; 49
int intY = 0; 50 if (p.Y + parentControl.Height + childControl.Height >
Screen.PrimaryScreen.Bounds.Height) 51 { 52 intY = p.Y - childControl.Height -
1; 53 blnDown = false; 54 } 55 else 56 { 57 intY = p.Y +
parentControl.Height +1; 58 blnDown = true; 59 } 60 61 if (p.X +
childControl.Width > Screen.PrimaryScreen.Bounds.Width) 62 { 63 intX =
Screen.PrimaryScreen.Bounds.Width - childControl.Width; 64 65 } 66 else 67
{ 68 intX = p.X; 69 } 70 if (deviation.HasValue) 71 { 72 intX +=
deviation.Value.X; 73 intY += deviation.Value.Y; 74 } 75 this.Location = new
Point(intX, intY); 76 } 77 78 public FrmAnchor(Control parentControl, Size
size, Point? deviation =null) 79 { 80 m_parentControl = parentControl; 81
InitializeComponent(); 82 this.Size = size; 83 this.HandleCreated +=
FrmDownBoard_HandleCreated; 84 this.HandleDestroyed +=
FrmDownBoard_HandleDestroyed; 85 86 Point p =
parentControl.Parent.PointToScreen(parentControl.Location); 87 int intX = 0; 88
int intY = 0; 89 if (p.Y + parentControl.Height + size.Height >
Screen.PrimaryScreen.Bounds.Height) 90 { 91 intY = p.Y - size.Height - 1; 92
blnDown =false; 93 } 94 else 95 { 96 intY = p.Y + parentControl.Height + 1
; 97 blnDown = true; 98 } 99 100 if (p.X + size.Width >
Screen.PrimaryScreen.Bounds.Width)101 { 102 intX =
Screen.PrimaryScreen.Bounds.Width - size.Width; 103 104 } 105 else 106 { 107
intX = p.X; 108 } 109 if (deviation.HasValue) 110 { 111 intX +=
deviation.Value.X;112 intY += deviation.Value.Y; 113 } 114 this.Location = new
Point(intX, intY);115 } 116 117 #endregion 118 119 private void
FrmDownBoard_HandleDestroyed(object sender, EventArgs e) 120 { 121
Application.RemoveMessageFilter(this); 122 } 123 124 private void
FrmDownBoard_HandleCreated(object sender, EventArgs e) 125 { 126
Application.AddMessageFilter(this); 127 } 128 129 #region 无焦点窗体 130 131
[System.Runtime.InteropServices.DllImport("user32.dll")] 132 private extern
static IntPtr SetActiveWindow(IntPtr handle); 133 private const int WM_ACTIVATE
=0x006; 134 private const int WM_ACTIVATEAPP = 0x01C; 135 private const int
WM_NCACTIVATE =0x086; 136 private const int WA_INACTIVE = 0; 137 private const
int WM_MOUSEACTIVATE = 0x21; 138 private const int MA_NOACTIVATE = 3; 139
protected override void WndProc(ref Message m) 140 { 141 if (m.Msg ==
WM_MOUSEACTIVATE)142 { 143 m.Result = new IntPtr(MA_NOACTIVATE); 144 return;
145 } 146 else if (m.Msg == WM_NCACTIVATE) 147 { 148 if (((int)m.WParam &
0xFFFF) != WA_INACTIVE) 149 { 150 if (m.LParam != IntPtr.Zero) 151 { 152
SetActiveWindow(m.LParam);153 } 154 else 155 { 156
SetActiveWindow(IntPtr.Zero);157 } 158 } 159 } 160 base.WndProc(ref m); 161
}162 163 #endregion 164 165 public bool PreFilterMessage(ref Message m) 166 {
167 if (m.Msg != 0x0201 || this.Visible == false) 168 return false; 169 var pt =
this.PointToClient(MousePosition); 170 this.Visible = this
.ClientRectangle.Contains(pt);171 return false; 172 } 173 174 private void
FrmAnchor_Load(object sender, EventArgs e) 175 { 176 177 } 178 179 180 private
void FrmAnchor_VisibleChanged(object sender, EventArgs e) 181 { 182
timer1.Enabled =this.Visible; 183 if (Visible) 184 { 185 if (blnDown) 186
ControlHelper.AnimateWindow(this.Handle, 100, ControlHelper.AW_VER_POSITIVE);
187 else 188 { 189 ControlHelper.AnimateWindow(this.Handle, 100,
ControlHelper.AW_VER_NEGATIVE);190 } 191 } 192 else 193 { 194 if (blnDown)
195 ControlHelper.AnimateWindow(this.Handle, 100, ControlHelper.AW_VER_NEGATIVE
| ControlHelper.AW_HIDE); 196 else 197 { 198 ControlHelper.AnimateWindow(this
.Handle,100, ControlHelper.AW_VER_POSITIVE | ControlHelper.AW_HIDE); 199 200 }
201 } 202 } 203 204 private void timer1_Tick(object sender, EventArgs e) 205
{206 if (this.Owner != null) 207 { 208 Form frm = this.Owner as Form; 209
IntPtr _ptr = ControlHelper.GetForegroundWindow(); 210 if (_ptr != frm.Handle)
211 { 212 this.Hide(); 213 } 214 } 215 } 216 217 } 218 } View Code 1
namespace HZH_Controls.Forms 2 { 3 partial class FrmAnchor 4 { 5 ///
<summary> 6 /// Required designer variable. 7 /// </summary> 8 private
System.ComponentModel.IContainer components =null; 9 10 /// <summary> 11 ///
Clean up any resources being used.12 /// </summary> 13 /// <param
name="disposing">true if managed resources should be disposed; otherwise, false.
</param> 14 protected override void Dispose(bool disposing) 15 { 16 if
(disposing && (components !=null)) 17 { 18 components.Dispose(); 19 } 20 base
.Dispose(disposing);21 } 22 23 #region Windows Form Designer generated code 24
25 /// <summary> 26 /// Required method for Designer support - do not modify 27
/// the contents of this method with the code editor. 28 /// </summary> 29
private void InitializeComponent() 30 { 31 this.components = new
System.ComponentModel.Container();32
System.ComponentModel.ComponentResourceManager resources =new
System.ComponentModel.ComponentResourceManager(typeof(FrmAnchor)); 33 this
.timer1 =new System.Windows.Forms.Timer(this.components); 34 this
.SuspendLayout();35 // 36 // timer1 37 // 38 this.timer1.Tick += new
System.EventHandler(this.timer1_Tick); 39 // 40 // FrmAnchor 41 // 42 this
.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 43 this.ClientSize =
new System.Drawing.Size(45, 48); 44 this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.None;45 this.Icon =
((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 46 this.Name = "
FrmAnchor"; 47 this.ShowIcon = false; 48 this.ShowInTaskbar = false; 49 this
.StartPosition = System.Windows.Forms.FormStartPosition.Manual; 50 this.Text = "
FrmAnchor"; 51 this.TopMost = true; 52 this.Load += new System.EventHandler(this
.FrmAnchor_Load);53 this.VisibleChanged += new System.EventHandler(this
.FrmAnchor_VisibleChanged);54 this.ResumeLayout(false); 55 56 } 57 58
#endregion 59 60 private System.Windows.Forms.Timer timer1; 61 } 62 } View Code
用处及效果

用处:弹出菜单,文本框弹出键盘等

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control
<https://gitee.com/kwwwvagaa/net_winform_custom_control> 点个星 星吧