前提
入行已经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> 点个星 星吧
热门工具 换一换