前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
欢迎前来交流探讨: 企鹅群568015492
目录
https://www.cnblogs.com/bfyx/p/11364884.html
准备工作
这是一个可停靠在指定位置或停靠在某个控件旁边的无焦点窗体,市区焦点会关闭
开始
添加一个Form,命名为FrmAnchor,实现接口IMessageFilter
有2个构造函数
1 #region 构造函数 2 ///3 /// 功能描述:构造函数 4 /// 作 者:HZH 5 /// 创建日期:2019-02-27 11:49:08 6 /// 任务编号:POS 7 /// 8 /// 父控件 9 /// 子控件 10 /// 偏移 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 ///19 /// 功能描述:停靠窗体 20 /// 作 者:HZH 21 /// 创建日期:2019-02-27 11:49:03 22 /// 任务编号:POS 23 /// 24 public partial class FrmAnchor : Form, IMessageFilter 25 { 26 Control m_parentControl = null; 27 private bool blnDown = true; 28 #region 构造函数 29 /// 30 /// 功能描述:构造函数 31 /// 作 者:HZH 32 /// 创建日期:2019-02-27 11:49:08 33 /// 任务编号:POS 34 /// 35 /// 父控件 36 /// 子控件 37 /// 偏移 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 }
1 namespace HZH_Controls.Forms 2 { 3 partial class FrmAnchor 4 { 5 ///6 /// Required designer variable. 7 /// 8 private System.ComponentModel.IContainer components = null; 9 10 /// 11 /// Clean up any resources being used. 12 /// 13 /// true if managed resources should be disposed; otherwise, false. 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 /// 26 /// Required method for Designer support - do not modify 27 /// the contents of this method with the code editor. 28 /// 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 }
用处及效果
用处:弹出菜单,文本框弹出键盘等
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧