├── .gitignore ├── .tfignore ├── CustomControls ├── CheckGroupBox.cs ├── CheckableGroupBox.cs ├── IRadioControl.cs ├── MessageBoxEx.cs └── RadioGroupBox.cs ├── DialogDragger.cs ├── FmMDI.Designer.cs ├── FmMDI.cs ├── FmMDI.resx ├── FmTabMDI.Designer.cs ├── FmTabMDI.cs ├── FmTabMDI.resx ├── FmTabSub.Designer.cs ├── FmTabSub.cs ├── FmTabSub.resx ├── FmTestDrag.Designer.cs ├── FmTestDrag.cs ├── FmTestDrag.resx ├── FormDragger.cs ├── FormDraggerDemo.csproj ├── FormDraggerDemo.sln ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── README.md └── pic.png /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | *.obj 3 | *.exe 4 | *.pdb 5 | *.user 6 | *.aps 7 | *.pch 8 | *.vspscc 9 | *_i.c 10 | *_p.c 11 | *.ncb 12 | *.suo 13 | *.sln.docstates 14 | *.tlb 15 | *.tlh 16 | *.bak 17 | *.cache 18 | *.ilk 19 | *.log 20 | [Bb]in 21 | [Dd]ebug*/ 22 | *.lib 23 | *.sbr 24 | obj/ 25 | [Rr]elease*/ 26 | _ReSharper*/ 27 | [Tt]est[Rr]esult* 28 | *.vssscc 29 | $tf*/ 30 | .vs/ -------------------------------------------------------------------------------- /.tfignore: -------------------------------------------------------------------------------- 1 | \.git -------------------------------------------------------------------------------- /CustomControls/CheckGroupBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace AhDung.WinForm.Controls 6 | { 7 | /// 8 | /// 复选组面板 9 | /// 10 | [ToolboxItem(true)] 11 | public class CheckGroupBox : CheckableGroupBox 12 | { 13 | CheckBox CheckBoxControl 14 | { 15 | get { return (CheckBox)CheckControl; } 16 | } 17 | 18 | /// 19 | /// 获取或设置勾选状态 20 | /// 21 | [Description("勾选状态")] 22 | [DefaultValue(CheckState.Unchecked)] 23 | public CheckState CheckState 24 | { 25 | get { return CheckBoxControl.CheckState; } 26 | set { CheckBoxControl.CheckState = value; } 27 | } 28 | 29 | /// 30 | /// 获取或设置是否允许三态 31 | /// 32 | [Description("是否允许三态")] 33 | [DefaultValue(false)] 34 | public bool ThreeState 35 | { 36 | get { return CheckBoxControl.ThreeState; } 37 | set { CheckBoxControl.ThreeState = value; } 38 | } 39 | 40 | /// 41 | /// 选中状态改变后 42 | /// 43 | public event EventHandler CheckStateChanged; 44 | 45 | /// 46 | /// 初始化本类 47 | /// 48 | public CheckGroupBox() 49 | : base(true) 50 | { 51 | CheckBoxControl.CheckStateChanged += checkControl_CheckStateChanged; 52 | } 53 | 54 | protected virtual void OnCheckStateChanged(EventArgs e) 55 | { 56 | var handler = CheckStateChanged; 57 | if (handler != null) 58 | { 59 | handler(this, e); 60 | } 61 | } 62 | 63 | void checkControl_CheckStateChanged(object sender, EventArgs e) 64 | { 65 | OnCheckStateChanged(EventArgs.Empty); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /CustomControls/CheckableGroupBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using System.Windows.Forms.Design; 6 | 7 | namespace AhDung.WinForm.Controls 8 | { 9 | /// 10 | /// 可Check的分组框 11 | /// 12 | [Designer(typeof(CheckableGroupBoxDesigner))] 13 | [ToolboxItem(false)] 14 | [DefaultEvent("CheckedChanged")] 15 | [DefaultProperty("Checked")] 16 | public class CheckableGroupBox : UserControl 17 | { 18 | readonly bool _isCheckBox; 19 | protected ButtonBase CheckControl; 20 | GroupBoxInner _grpBox; 21 | bool _autoDisableContent; 22 | Color _titleColor; 23 | 24 | /// 25 | /// 获取或设置文本 26 | /// 27 | [Description("抬头文字")] 28 | [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)] //不是蛋疼 29 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] //不是蛋疼 30 | public override string Text 31 | { 32 | get { return CheckControl.Text; } 33 | set { CheckControl.Text = value; } 34 | } 35 | 36 | /// 37 | /// 获取或设置标题颜色 38 | /// 39 | [Description("标题颜色")] 40 | [DefaultValue(typeof(Color), "0, 70, 213")] 41 | public Color TitleColor 42 | { 43 | get { return _titleColor; } 44 | set 45 | { 46 | if (_titleColor == value) { return; } 47 | _titleColor = value; 48 | CheckControl.ForeColor = _titleColor; 49 | } 50 | } 51 | 52 | /// 53 | /// 获取或设置是否勾选 54 | /// 55 | [Description("是否勾选")] 56 | [DefaultValue(false)] 57 | public bool Checked 58 | { 59 | get 60 | { 61 | return _isCheckBox 62 | ? ((CheckBox)CheckControl).Checked 63 | : ((RadioButton)CheckControl).Checked; 64 | } 65 | set 66 | { 67 | if (_isCheckBox) 68 | { 69 | ((CheckBox)CheckControl).Checked = value; 70 | } 71 | else 72 | { 73 | ((RadioButton)CheckControl).Checked = value; 74 | } 75 | } 76 | } 77 | 78 | [Description("取消Checked时是否屏蔽内容区")] 79 | [EditorBrowsable(EditorBrowsableState.Never)] 80 | [DefaultValue(true)] 81 | public bool AutoDisableContent 82 | { 83 | get { return _autoDisableContent; } 84 | set 85 | { 86 | if (_autoDisableContent == value) { return; } 87 | _autoDisableContent = value; 88 | if (!_autoDisableContent)//当开闭状态不联动时,强制开启 89 | { 90 | _grpBox.Enabled = true; 91 | } 92 | } 93 | } 94 | 95 | /// 96 | /// 是否选中改变后 97 | /// 98 | public event EventHandler CheckedChanged; 99 | 100 | [Browsable(false)] 101 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 102 | public GroupBoxInner GroupBoxControl 103 | { 104 | get { return _grpBox; } 105 | } 106 | 107 | /// 108 | /// 初始化本类 109 | /// 110 | /// true为复选框,false为单选框 111 | protected CheckableGroupBox(bool isCheckBox) 112 | { 113 | _isCheckBox = isCheckBox; 114 | _titleColor = Color.FromArgb(0, 70, 213); 115 | InitializeComponent(); 116 | AutoDisableContent = true; 117 | _grpBox.Enabled = false; 118 | } 119 | 120 | private void InitializeComponent() 121 | { 122 | this._grpBox = new GroupBoxInner(); 123 | this.SuspendLayout(); 124 | this._grpBox.SuspendLayout(); 125 | // 126 | // CheckControl 127 | // 128 | if (_isCheckBox) 129 | { 130 | CheckControl = new CheckBox(); 131 | ((CheckBox)CheckControl).CheckedChanged += checkControl_CheckedChanged; 132 | } 133 | else 134 | { 135 | CheckControl = new RadioButton(); 136 | ((RadioButton)CheckControl).CheckedChanged += checkControl_CheckedChanged; 137 | } 138 | this.CheckControl.AutoSize = true; 139 | this.CheckControl.ForeColor = _titleColor; 140 | this.CheckControl.Location = new System.Drawing.Point(8, -1); 141 | this.CheckControl.Name = "CheckControl"; 142 | this.CheckControl.TabIndex = 0; 143 | // 144 | // _grpBox 145 | // 146 | this._grpBox.Dock = System.Windows.Forms.DockStyle.Fill; 147 | this._grpBox.Name = "_grpBox"; 148 | this._grpBox.TabIndex = 1; 149 | // 150 | // CheckedGroupBox 151 | // 152 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 153 | this.Controls.Add(CheckControl); 154 | this.Controls.Add(this._grpBox); 155 | this._grpBox.ResumeLayout(false); 156 | this.ResumeLayout(false); 157 | this.PerformLayout(); 158 | } 159 | 160 | protected virtual void OnCheckedChanged(EventArgs e) 161 | { 162 | var handler = CheckedChanged; 163 | if (handler != null) 164 | { 165 | handler(this, e); 166 | } 167 | } 168 | 169 | void checkControl_CheckedChanged(object sender, EventArgs e) 170 | { 171 | if (AutoDisableContent) 172 | { 173 | _grpBox.Enabled = this.Checked; 174 | } 175 | OnCheckedChanged(EventArgs.Empty); 176 | } 177 | 178 | [ToolboxItem(false)] 179 | public class GroupBoxInner : GroupBox 180 | { 181 | // ReSharper disable UnusedMember.Global 182 | [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 183 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 184 | public override DockStyle Dock 185 | { 186 | get { return base.Dock; } 187 | set { base.Dock = value; } 188 | } 189 | 190 | [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 191 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 192 | public new bool Enabled 193 | { 194 | get { return base.Enabled; } 195 | set { base.Enabled = value; } 196 | } 197 | 198 | [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 199 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 200 | public new Point Location 201 | { 202 | get { return base.Location; } 203 | set { base.Location = value; } 204 | } 205 | 206 | [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 207 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 208 | public new string Name 209 | { 210 | get { return base.Name; } 211 | set { base.Name = value; } 212 | } 213 | 214 | [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 215 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 216 | public new int TabIndex 217 | { 218 | get { return base.TabIndex; } 219 | set { base.TabIndex = value; } 220 | } 221 | 222 | [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 223 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 224 | public new bool TabStop 225 | { 226 | get { return base.TabStop; } 227 | set { base.TabStop = value; } 228 | } 229 | 230 | [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 231 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 232 | public override string Text 233 | { 234 | get { return base.Text; } 235 | set { base.Text = value; } 236 | } 237 | // ReSharper restore UnusedMember.Global 238 | } 239 | } 240 | 241 | public class CheckableGroupBoxDesigner : ParentControlDesigner 242 | { 243 | public override void Initialize(IComponent component) 244 | { 245 | base.Initialize(component); 246 | 247 | if (this.Control is CheckableGroupBox) 248 | { 249 | EnableDesignMode(((CheckableGroupBox)this.Control).GroupBoxControl, "GroupBoxControl"); 250 | } 251 | } 252 | } 253 | } 254 | 255 | 256 | -------------------------------------------------------------------------------- /CustomControls/IRadioControl.cs: -------------------------------------------------------------------------------- 1 | namespace AhDung.WinForm 2 | { 3 | /// 4 | /// 单选互斥类控件 5 | /// 6 | interface IRadioControl 7 | { 8 | /// 9 | /// 获取或设置选中状态 10 | /// 11 | bool Checked { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /CustomControls/MessageBoxEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | using System.Threading; 7 | using System.Windows.Forms; 8 | 9 | namespace AhDung.WinForm 10 | { 11 | /// 12 | /// 可以携带详细信息的消息框 13 | /// 14 | public static class MessageBoxEx 15 | { 16 | //异常消息文本 17 | private const string InvalidButtonExString = "按钮参数不是有效的枚举项!"; 18 | private const string InvalidIconExString = "图标参数不是有效的枚举项!"; 19 | private const string InvalidDfButtonExString = "默认按钮参数不是有效的枚举项!"; 20 | 21 | /// 22 | /// 是否启用动画效果 23 | /// 24 | public static bool EnableAnimate { get; set; } 25 | 26 | /// 27 | /// 是否启用声音反馈 28 | /// 29 | public static bool EnableSound { get; set; } 30 | 31 | //静态构造 32 | static MessageBoxEx() 33 | { 34 | //默认启用动画+声音 35 | EnableAnimate = true; 36 | EnableSound = true; 37 | } 38 | 39 | #region 公开方法 40 | 41 | /// 42 | /// 显示消息框 43 | /// 44 | /// 消息文本 45 | /// 消息框标题 46 | /// 附加消息 47 | public static DialogResult Show(string message, string caption = null, string attachMessage = null) 48 | { 49 | return ShowCore(message, caption, attachMessage, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); 50 | } 51 | 52 | /*下面这仨弄成重载而不是可选方法是为了避免不必要的参数检查*/ 53 | 54 | /// 55 | /// 显示消息框 56 | /// 57 | /// 消息文本 58 | /// 消息框标题 59 | /// 附加消息 60 | /// 按钮组合 61 | public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons) 62 | { 63 | if (!Enum.IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); } 64 | 65 | return ShowCore(message, caption, attachMessage, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); 66 | } 67 | 68 | /// 69 | /// 显示消息框 70 | /// 71 | /// 消息文本 72 | /// 消息框标题 73 | /// 附加消息 74 | /// 按钮组合 75 | /// 图标 76 | public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon) 77 | { 78 | if (!Enum.IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); } 79 | if (!Enum.IsDefined(typeof(MessageBoxIcon), icon)) { throw new InvalidEnumArgumentException(InvalidIconExString); } 80 | 81 | return ShowCore(message, caption, attachMessage, buttons, icon, MessageBoxDefaultButton.Button1); 82 | } 83 | 84 | /// 85 | /// 显示消息框 86 | /// 87 | /// 消息文本 88 | /// 消息框标题 89 | /// 附加消息 90 | /// 按钮组合 91 | /// 图标 92 | /// 默认按钮 93 | public static DialogResult Show(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) 94 | { 95 | if (!Enum.IsDefined(typeof(MessageBoxButtons), buttons)) { throw new InvalidEnumArgumentException(InvalidButtonExString); } 96 | if (!Enum.IsDefined(typeof(MessageBoxIcon), icon)) { throw new InvalidEnumArgumentException(InvalidIconExString); } 97 | if (!Enum.IsDefined(typeof(MessageBoxDefaultButton), defaultButton)) { throw new InvalidEnumArgumentException(InvalidDfButtonExString); } 98 | 99 | return ShowCore(message, caption, attachMessage, buttons, icon, defaultButton); 100 | } 101 | 102 | /********传入异常的重载********/ 103 | 104 | /// 105 | /// 显示消息框 106 | /// 107 | /// 消息文本 108 | /// 消息框标题 109 | /// 异常实例 110 | public static DialogResult Show(string message, string caption, Exception exception) 111 | { 112 | return Show(message, caption, exception == null ? string.Empty : exception.ToString()); 113 | } 114 | 115 | /// 116 | /// 显示消息框 117 | /// 118 | /// 消息文本 119 | /// 消息框标题 120 | /// 异常实例 121 | /// 按钮组合 122 | public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons) 123 | { 124 | return Show(message, caption, exception == null ? string.Empty : exception.ToString(), buttons); 125 | } 126 | 127 | /// 128 | /// 显示消息框 129 | /// 130 | /// 消息文本 131 | /// 消息框标题 132 | /// 异常实例 133 | /// 按钮组合 134 | /// 图标 135 | public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons, MessageBoxIcon icon) 136 | { 137 | return Show(message, caption, exception == null ? string.Empty : exception.ToString(), buttons, icon); 138 | } 139 | 140 | /// 141 | /// 显示消息框 142 | /// 143 | /// 消息文本 144 | /// 消息框标题 145 | /// 异常实例 146 | /// 按钮组合 147 | /// 图标 148 | /// 默认按钮 149 | public static DialogResult Show(string message, string caption, Exception exception, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) 150 | { 151 | return Show(message, caption, exception == null ? string.Empty : exception.ToString(), buttons, icon, defaultButton); 152 | } 153 | 154 | #endregion 155 | 156 | //内部方法,不检查参数有效性 157 | private static DialogResult ShowCore(string message, string caption, string attachMessage, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) 158 | { 159 | using (MessageForm f = new MessageForm(message, caption, buttons, icon, defaultButton, attachMessage, EnableAnimate, EnableSound)) 160 | { 161 | return f.ShowDialog(); 162 | } 163 | } 164 | 165 | 166 | /*---------------- 167 | 下面是消息窗体相关 168 | ---------------*/ 169 | 170 | /// 171 | /// 消息窗体 172 | /// 173 | /// 参数有效性由MessageBoxEx负责 174 | private class MessageForm : Form 175 | { 176 | /* todo 存在问题: 177 | * 当消息区文本非常非常多时,且反复进行改变消息框窗口大小、位置、展开收起的操作,那么在某次展开时 178 | 详细信息文本框可能会在原位置(即消息区内某rect)瞬闪一下, 179 | 原因是文本框控件在显示时总会在原位置WM_NCPAINT + WM_ERASEBKGND一下,暂无解决办法。 180 | 实际应用中碰到的几率很小,就算碰到,影响也可以忽略。 181 | */ 182 | 183 | #region 控件初始化 184 | 185 | /// 186 | /// 必需的设计器变量。 187 | /// 188 | private System.ComponentModel.IContainer components = null; 189 | 190 | /// 191 | /// 清理所有正在使用的资源。 192 | /// 193 | /// 如果应释放托管资源,为 true;否则为 false。 194 | protected override void Dispose(bool disposing) 195 | { 196 | if (disposing && (components != null)) 197 | { 198 | components.Dispose(); 199 | } 200 | base.Dispose(disposing); 201 | } 202 | 203 | #region Windows 窗体设计器生成的代码 204 | 205 | /// 206 | /// 设计器支持所需的方法 - 不要 207 | /// 使用代码编辑器修改此方法的内容。 208 | /// 209 | private void InitializeComponent() 210 | { 211 | this.button3 = new System.Windows.Forms.Button(); 212 | this.txbAttach = new TextBoxUnSelectAllable(); 213 | this.button2 = new System.Windows.Forms.Button(); 214 | this.button1 = new System.Windows.Forms.Button(); 215 | this.plButtonsZone = new AhDung.WinForm.MessageBoxEx.MessageForm.PanelBasic(); 216 | this.ckbToggle = new AhDung.WinForm.MessageBoxEx.MessageForm.ToggleButton(this.UseAnimate); 217 | this.plAttachZone = new AhDung.WinForm.MessageBoxEx.MessageForm.PanelBasic(); 218 | this.lbMsg = new AhDung.WinForm.MessageBoxEx.MessageForm.MessageViewer(); 219 | this.plButtonsZone.SuspendLayout(); 220 | this.plAttachZone.SuspendLayout(); 221 | this.SuspendLayout(); 222 | // 223 | // button3 224 | // 225 | this.button3.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; 226 | this.button3.Location = new System.Drawing.Point(320, 8); 227 | this.button3.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); 228 | this.button3.Name = "button3"; 229 | this.button3.Size = new System.Drawing.Size(85, 27); 230 | this.button3.TabIndex = 2; 231 | // 232 | // txbAttach 233 | // 234 | this.txbAttach.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 235 | | System.Windows.Forms.AnchorStyles.Left) 236 | | System.Windows.Forms.AnchorStyles.Right; 237 | this.txbAttach.Location = new System.Drawing.Point(10, 7); 238 | this.txbAttach.Margin = new System.Windows.Forms.Padding(3, 1, 3, 1); 239 | this.txbAttach.Name = "txbAttach"; 240 | this.txbAttach.ReadOnly = true; 241 | this.txbAttach.Multiline = true; 242 | this.txbAttach.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 243 | this.txbAttach.Size = new System.Drawing.Size(395, 105); 244 | this.txbAttach.TabIndex = 0; 245 | // 246 | // button2 247 | // 248 | this.button2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; 249 | this.button2.Location = new System.Drawing.Point(229, 8); 250 | this.button2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); 251 | this.button2.Name = "button2"; 252 | this.button2.Size = new System.Drawing.Size(85, 27); 253 | this.button2.TabIndex = 1; 254 | // 255 | // button1 256 | // 257 | this.button1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; 258 | this.button1.Location = new System.Drawing.Point(138, 8); 259 | this.button1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); 260 | this.button1.Name = "button1"; 261 | this.button1.Size = new System.Drawing.Size(85, 27); 262 | this.button1.TabIndex = 0; 263 | // 264 | // plButtonsZone 265 | // 266 | this.plButtonsZone.Controls.Add(this.ckbToggle); 267 | this.plButtonsZone.Controls.Add(this.button1); 268 | this.plButtonsZone.Controls.Add(this.button2); 269 | this.plButtonsZone.Controls.Add(this.button3); 270 | this.plButtonsZone.Dock = System.Windows.Forms.DockStyle.Bottom; 271 | this.plButtonsZone.Location = new System.Drawing.Point(0, 96); 272 | this.plButtonsZone.Margin = new System.Windows.Forms.Padding(3, 1, 3, 1); 273 | this.plButtonsZone.Name = "plButtonsZone"; 274 | this.plButtonsZone.Size = new System.Drawing.Size(415, 36); 275 | this.plButtonsZone.TabIndex = 1; 276 | // 277 | // ckbToggle 278 | // 279 | this.ckbToggle.Location = new System.Drawing.Point(10, 8); 280 | this.ckbToggle.Name = "ckbToggle"; 281 | this.ckbToggle.Size = new System.Drawing.Size(93, 27); 282 | this.ckbToggle.TabIndex = 3; 283 | this.ckbToggle.Text = "详细信息(&D)"; 284 | this.ckbToggle.CheckedChanged += this.ckbToggle_CheckedChanged; 285 | // 286 | // plAttachZone 287 | // 288 | this.plAttachZone.Controls.Add(this.txbAttach); 289 | this.plAttachZone.Dock = System.Windows.Forms.DockStyle.Fill; 290 | this.plAttachZone.Location = new System.Drawing.Point(0, 130); 291 | this.plAttachZone.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); 292 | this.plAttachZone.Name = "plAttachZone"; 293 | this.plAttachZone.Size = new System.Drawing.Size(415, 114); 294 | this.plAttachZone.TabIndex = 2; 295 | this.plAttachZone.Visible = false; 296 | // 297 | // lbMsg 298 | // 299 | this.lbMsg.Dock = System.Windows.Forms.DockStyle.Fill; 300 | this.lbMsg.Icon = null; 301 | this.lbMsg.Location = new System.Drawing.Point(0, 0); 302 | this.lbMsg.Name = "lbMsg"; 303 | this.lbMsg.Padding = new System.Windows.Forms.Padding(21, 18, 21, 18); 304 | //this.lbMsg.Size = new System.Drawing.Size(415, 96); 305 | this.lbMsg.TabIndex = 0; 306 | // 307 | // FmMsg 308 | // 309 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 310 | //this.ClientSize = new System.Drawing.Size(415, 261); 311 | this.Controls.Add(this.lbMsg); 312 | this.Controls.Add(this.plButtonsZone); 313 | this.Controls.Add(this.plAttachZone); 314 | this.DoubleBuffered = true; 315 | this.MaximizeBox = false; 316 | this.Name = "MessageForm"; 317 | this.Padding = new System.Windows.Forms.Padding(0, 0, 0, 17); 318 | this.ShowIcon = false; 319 | this.ShowInTaskbar = false; 320 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; 321 | this.plButtonsZone.ResumeLayout(false); 322 | this.plAttachZone.ResumeLayout(false); 323 | this.plAttachZone.PerformLayout(); 324 | this.ResumeLayout(false); 325 | } 326 | 327 | #endregion 328 | 329 | private ToggleButton ckbToggle; 330 | private TextBoxUnSelectAllable txbAttach; 331 | private MessageViewer lbMsg; 332 | private System.Windows.Forms.Button button2; 333 | private System.Windows.Forms.Button button1; 334 | private PanelBasic plButtonsZone; 335 | private PanelBasic plAttachZone; 336 | private System.Windows.Forms.Button button3; 337 | 338 | #endregion 339 | 340 | /// 341 | /// 最大默认窗体客户区宽度 342 | /// 343 | const int MaxClientWidth = 700; 344 | 345 | string messageSound;//存储供PlaySound API使用的系统消息音别名,在ProcessIcon中赋值,OnShown中取用 346 | 347 | int expandHeight; 348 | /// 349 | /// 详细信息区展开高度 350 | /// 351 | private int ExpandHeight 352 | { 353 | get { return expandHeight < 150 ? 150 : expandHeight; } 354 | set { expandHeight = value; } 355 | } 356 | 357 | #region 属性 358 | 359 | /// 360 | /// 是否启用动画效果 361 | /// 362 | /// 此处还弄该属性是为了保证窗体类的独立性 363 | private bool UseAnimate { get; set; } 364 | 365 | /// 366 | /// 是否启用声音反馈 367 | /// 368 | /// 此处还弄该属性是为了保证窗体类的独立性 369 | private bool UseSound { get; set; } 370 | 371 | /// 372 | /// 消息按钮 373 | /// 374 | private MessageBoxButtons MessageButtons { get; set; } 375 | 376 | /// 377 | /// 消息图标 378 | /// 379 | private MessageBoxIcon MessageIcon { get; set; } 380 | 381 | /// 382 | /// 默认按钮 383 | /// 384 | private MessageBoxDefaultButton DefaultButton { get; set; } 385 | 386 | #endregion 387 | 388 | /// 389 | /// 创建消息窗体 390 | /// 391 | private MessageForm(bool enableAnimate) 392 | { 393 | this.UseAnimate = enableAnimate;//须尽早设置,要供展开按钮初始化用 394 | InitializeComponent(); 395 | this.StartPosition = Form.ActiveForm == null ? FormStartPosition.CenterScreen : FormStartPosition.CenterParent; 396 | this.Font = SystemFonts.MessageBoxFont; 397 | 398 | //注册事件 399 | this.button1.Click += button_Click; 400 | this.button2.Click += button_Click; 401 | this.button3.Click += button_Click; 402 | this.plAttachZone.Resize += plAttachZone_Resize; 403 | } 404 | 405 | /// 406 | /// 创建消息窗体 407 | /// 408 | public MessageForm(string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, string attachMessage, bool enableAnimate, bool enableSound) 409 | : this(enableAnimate) 410 | { 411 | this.lbMsg.Text = message; 412 | this.Text = caption; 413 | this.txbAttach.Text = attachMessage; 414 | this.MessageButtons = buttons; 415 | this.MessageIcon = icon; 416 | this.DefaultButton = defaultButton; 417 | this.UseSound = enableSound; 418 | } 419 | 420 | #region 重写基类方法 421 | 422 | protected override void OnLoad(EventArgs e) 423 | { 424 | //须在计算各种尺寸前搞掂 425 | ProcessIcon(); 426 | ProcessButtons(); 427 | 428 | this.MinimumSize = SizeFromClientSize(new Size(GetPanelButtonMinWidth(), GetClientMinHeight())); 429 | 430 | //参数意义定为客户区最大大小,所以需刨掉非客户区高度后传入 431 | this.ClientSize = this.GetPreferredSize(new Size(MaxClientWidth, Screen.PrimaryScreen.WorkingArea.Height - (this.Height - this.ClientSize.Height))); 432 | 433 | base.OnLoad(e); 434 | } 435 | 436 | protected override void OnShown(EventArgs e) 437 | { 438 | //设置默认按钮焦点。须在OnShown中设置按钮焦点才有用 439 | Button dfBtn; 440 | if ((dfBtn = this.AcceptButton as Button) != null) 441 | { 442 | dfBtn.Focus(); 443 | } 444 | 445 | //播放消息提示音 446 | if (this.UseSound) { PlaySystemSound(this.messageSound); } 447 | 448 | base.OnShown(e); 449 | } 450 | 451 | //重写窗体参数 452 | protected override CreateParams CreateParams 453 | { 454 | get 455 | { 456 | CreateParams prms = base.CreateParams; 457 | 458 | if ((Convert.ToInt32(this.MessageButtons) & 1) == 0) //没有Cancel按钮时屏蔽关闭按钮,刚好在偶数项 459 | { 460 | prms.ClassStyle |= 0x200; 461 | } 462 | 463 | return prms; 464 | } 465 | } 466 | 467 | /// 468 | /// 计算合适的窗口尺寸 469 | /// 470 | /// 该参数此处定义为客户区可设置的最大尺寸 471 | public override Size GetPreferredSize(Size proposedSize) 472 | { 473 | int reservedHeight = plButtonsZone.Height + Padding.Bottom; 474 | Size size = lbMsg.GetPreferredSize(new Size(proposedSize.Width, proposedSize.Height - reservedHeight)); 475 | size.Height += reservedHeight; 476 | return size; 477 | } 478 | 479 | #endregion 480 | 481 | #region 事件处理方法 482 | 483 | //展开收起 484 | private void ckbToggle_CheckedChanged(object sender, EventArgs e) 485 | { 486 | this.SuspendLayout(); 487 | 488 | if (ckbToggle.Checked) 489 | { 490 | plButtonsZone.SendToBack(); 491 | lbMsg.SendToBack(); 492 | 493 | lbMsg.Dock = DockStyle.Top; 494 | plButtonsZone.Dock = DockStyle.Top; 495 | 496 | ChangeFormHeight(ExpandHeight); 497 | plAttachZone.Visible = true; 498 | } 499 | else 500 | { 501 | ExpandHeight = plAttachZone.Height;//为再次展开记忆高度 502 | plAttachZone.Visible = false; 503 | ChangeFormHeight(-plAttachZone.Height);//收起时直接取pl高度,不要取ExpandHeight 504 | 505 | plButtonsZone.SendToBack(); 506 | 507 | plButtonsZone.Dock = DockStyle.Bottom; 508 | lbMsg.Dock = DockStyle.Fill; 509 | } 510 | 511 | this.ResumeLayout(); 512 | } 513 | 514 | //按钮事件 515 | private void button_Click(object sender, EventArgs e) 516 | { 517 | this.DialogResult = (DialogResult)((sender as Button).Tag); 518 | } 519 | 520 | //用户手工收完详细区则触发折叠 521 | private void plAttachZone_Resize(object sender, EventArgs e) 522 | { 523 | if (ckbToggle.Checked && plAttachZone.Height == 0) 524 | { 525 | ckbToggle.Checked = false; 526 | } 527 | } 528 | 529 | #endregion 530 | 531 | #region 辅助+私有方法 532 | 533 | /// 534 | /// 处理按钮相关 535 | /// 536 | private void ProcessButtons() 537 | { 538 | this.ckbToggle.Visible = txbAttach.Text.Trim().Length != 0; //无详细信息就不显示展开按钮 539 | 540 | int btnCount = 3; //按钮数量 541 | 542 | switch (MessageButtons) //老实用case,可读点。给确定和取消加了助记键 543 | { 544 | case MessageBoxButtons.AbortRetryIgnore: 545 | button1.Text = "中止(&A)"; button1.Tag = DialogResult.Abort; 546 | button2.Text = "重试(&R)"; button2.Tag = DialogResult.Retry; 547 | button3.Text = "忽略(&I)"; button3.Tag = DialogResult.Ignore; 548 | break; 549 | case MessageBoxButtons.OK: 550 | button1.Visible = false; 551 | button2.Visible = false; 552 | button3.Text = "确定(&O)"; button3.Tag = DialogResult.OK; 553 | btnCount = 1; 554 | break; 555 | case MessageBoxButtons.OKCancel: 556 | button1.Visible = false; 557 | button2.Text = "确定(&O)"; button2.Tag = DialogResult.OK; 558 | button3.Text = "取消(&C)"; button3.Tag = DialogResult.Cancel; 559 | btnCount = 2; 560 | break; 561 | case MessageBoxButtons.RetryCancel: 562 | button1.Visible = false; 563 | button2.Text = "重试(&R)"; button2.Tag = DialogResult.Retry; 564 | button3.Text = "取消(&C)"; button3.Tag = DialogResult.Cancel; 565 | btnCount = 2; 566 | break; 567 | case MessageBoxButtons.YesNo: 568 | button1.Visible = false; 569 | button2.Text = "是(&Y)"; button2.Tag = DialogResult.Yes; 570 | button3.Text = "否(&N)"; button3.Tag = DialogResult.No; 571 | btnCount = 2; 572 | break; 573 | case MessageBoxButtons.YesNoCancel: 574 | button1.Text = "是(&Y)"; button1.Tag = DialogResult.Yes; 575 | button2.Text = "否(&N)"; button2.Tag = DialogResult.No; 576 | button3.Text = "取消(&C)"; button3.Tag = DialogResult.Cancel; 577 | break; 578 | default: break; 579 | } 580 | 581 | //仅有OK和有取消按钮时设CancelButton 582 | if ((int)MessageButtons == 0 || ((int)MessageButtons & 1) == 1) 583 | { 584 | this.CancelButton = button3; 585 | } 586 | 587 | //处理默认按钮 588 | if (btnCount == 1) 589 | { 590 | this.AcceptButton = button3; 591 | } 592 | else if (btnCount == 2) 593 | { 594 | this.AcceptButton = DefaultButton == MessageBoxDefaultButton.Button2 ? button3 : button2; 595 | } 596 | else 597 | { 598 | Button[] btnArray = { button1, button2, button3 }; 599 | this.AcceptButton = btnArray[Convert.ToInt32(DefaultButton) / 0x100]; 600 | } 601 | } 602 | 603 | /// 604 | /// 处理图标(含声音) 605 | /// 606 | private void ProcessIcon() 607 | { 608 | switch (MessageIcon) 609 | { 610 | //MessageBoxIcon.Information同样 611 | case MessageBoxIcon.Asterisk: 612 | lbMsg.Icon = SystemIcons.Information; 613 | messageSound = "SystemAsterisk"; 614 | break; 615 | 616 | //MessageBoxIcon.Hand、MessageBoxIcon.Stop同样 617 | case MessageBoxIcon.Error: 618 | lbMsg.Icon = SystemIcons.Error; 619 | messageSound = "SystemHand"; 620 | break; 621 | 622 | //MessageBoxIcon.Warning同样 623 | case MessageBoxIcon.Exclamation: 624 | lbMsg.Icon = SystemIcons.Warning; 625 | messageSound = "SystemExclamation"; 626 | break; 627 | 628 | case MessageBoxIcon.Question: 629 | lbMsg.Icon = SystemIcons.Question; 630 | messageSound = "SystemAsterisk";//Question原本是没声音的,此实现让它蹭一下Information的 631 | break; 632 | 633 | default: //MessageBoxIcon.None 634 | lbMsg.Icon = null; 635 | messageSound = "SystemDefault"; 636 | break; 637 | } 638 | } 639 | 640 | /// 641 | /// 计算窗体客户区最小高度 642 | /// 643 | private int GetClientMinHeight() 644 | { 645 | return lbMsg.MinimumHeight + plButtonsZone.Height + Padding.Bottom; 646 | } 647 | 648 | /// 649 | /// 计算按钮区最小宽度 650 | /// 651 | private int GetPanelButtonMinWidth() 652 | { 653 | int r = 20 /*左右Padding*/, visibleCount = -1 /*因为两个以上才会有间距*/; 654 | 655 | if (ckbToggle.Visible) { r += ckbToggle.Width; visibleCount++; } 656 | if (button1.Visible) { r += button1.Width * 3; visibleCount += 3; } 657 | else if (button2.Visible) { r += button2.Width * 2; visibleCount += 2; } 658 | else { r += button3.Width; visibleCount++; } 659 | 660 | if (visibleCount != -1) { r += visibleCount * 6; } //按钮间距 661 | 662 | return r; 663 | } 664 | 665 | /// 666 | /// 改变窗体高度。内部有动画处理 667 | /// 668 | /// 增量(负数即为减小高度) 669 | private void ChangeFormHeight(int increment) 670 | { 671 | int finalHeight = this.Height + increment; //正确的目标高度 672 | 673 | if (!this.UseAnimate) //不使用动画 674 | { 675 | this.Height = finalHeight; 676 | return; 677 | } 678 | 679 | const int step = 8; //帧数 680 | 681 | for (int i = 0; i < step; i++) 682 | { 683 | if (i == step - 1) //最后一步直达目标 684 | { 685 | this.Height = finalHeight; 686 | return; 687 | } 688 | 689 | this.Height += increment / step; 690 | 691 | Application.DoEvents(); //必要 692 | Thread.Sleep(10); 693 | } 694 | } 695 | 696 | /// 697 | /// 播放系统事件声音 698 | /// 699 | /// 之所以不用MessageBeep API是因为这货在srv08上不出声,所以用PlaySound代替 700 | private static void PlaySystemSound(string soundAlias) 701 | { 702 | PlaySound(soundAlias, IntPtr.Zero, 0x10000 /*SND_ALIAS*/| 0x1 /*SND_ASYNC*/); 703 | } 704 | 705 | [DllImport("winmm.dll", CharSet = CharSet.Auto)] 706 | private static extern bool PlaySound([MarshalAs(UnmanagedType.LPWStr)] string soundName, IntPtr hmod, int soundFlags); 707 | 708 | #endregion 709 | 710 | #region 嵌套类 711 | 712 | /// 713 | /// 基础面板 714 | /// 715 | private class PanelBasic : Control 716 | { 717 | public PanelBasic() 718 | { 719 | SetStyle(ControlStyles.AllPaintingInWmPaint, false);//关键,不然其上的ToolBar不正常 720 | SetStyle(ControlStyles.OptimizedDoubleBuffer, true);//重要。不设置的话控件绘制不正常 721 | SetStyle(ControlStyles.ContainerControl, true); 722 | SetStyle(ControlStyles.Selectable, false); 723 | } 724 | 725 | protected override void WndProc(ref Message m) 726 | { 727 | //屏蔽WM_ERASEBKGND。防止显示时在原位置快闪 728 | //不能通过ControlStyles.AllPaintingInWmPaint=true屏蔽 729 | //会影响其上的ToolBar 730 | if (m.Msg == 0x14) { return; } 731 | 732 | base.WndProc(ref m); 733 | } 734 | 735 | protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) 736 | { 737 | //防Dock时面板短暂滞留在原位置 738 | base.SetBoundsCore(x, y, width, height, specified | BoundsSpecified.Y | BoundsSpecified.Width); 739 | } 740 | } 741 | 742 | /// 743 | /// 消息呈现控件 744 | /// 745 | private class MessageViewer : Control 746 | { 747 | const TextFormatFlags textFlags = TextFormatFlags.EndEllipsis //未完省略号 748 | | TextFormatFlags.WordBreak //允许换行 749 | | TextFormatFlags.NoPadding //无边距 750 | | TextFormatFlags.ExternalLeading //行间空白。NT5必须,不然文字挤在一起 751 | | TextFormatFlags.TextBoxControl; //避免半行 752 | 753 | const int IconSpace = 5; //图标与文本间距 754 | 755 | const float PreferredScale = 13;//最佳文本区块比例(宽/高) 756 | 757 | /// 758 | /// 最小高度。不要重写MinimumSize,那会在窗体移动和缩放时都会执行 759 | /// 760 | public int MinimumHeight 761 | { 762 | get 763 | { 764 | return (this.Icon != null ? Math.Max(this.Icon.Height, this.FontHeight) : this.FontHeight) + Padding.Vertical; 765 | } 766 | } 767 | 768 | /// 769 | /// 获取或设置图标 770 | /// 771 | public Icon Icon { get; set; } 772 | 773 | public MessageViewer() 774 | { 775 | this.SetStyle(ControlStyles.CacheText, true); 776 | this.SetStyle(ControlStyles.UserPaint, true); 777 | this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); 778 | this.SetStyle(ControlStyles.Selectable, false); 779 | this.SetStyle(ControlStyles.ResizeRedraw, true); //重要 780 | 781 | this.DoubleBuffered = true; //双缓冲 782 | BackColor = Environment.OSVersion.Version.Major == 5 ? SystemColors.Control : Color.White; 783 | } 784 | 785 | //防Dock改变尺寸 786 | protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) 787 | { 788 | base.SetBoundsCore(x, y, width, height, specified | BoundsSpecified.Size); 789 | } 790 | 791 | /// 792 | /// 计算合适的消息区尺寸 793 | /// 794 | /// 该参数此处定义为此控件可设置的最大尺寸 795 | /// 该方法对太长的单行文本有做比例优化处理,避免用户摆头幅度过大扭到脖子 796 | public override Size GetPreferredSize(Size proposedSize) 797 | { 798 | if (proposedSize.Width < 10) { proposedSize.Width = int.MaxValue; } 799 | if (proposedSize.Height < 10) { proposedSize.Height = int.MaxValue; } 800 | 801 | int reservedWidth = Padding.Horizontal + (this.Icon == null ? 0 : (this.Icon.Width + IconSpace)); 802 | 803 | Size wellSize = Size.Empty; 804 | if (!string.IsNullOrEmpty(this.Text)) 805 | { 806 | //优化文本块宽高比例 807 | Size size = TextRenderer.MeasureText(this.Text, this.Font, new Size(proposedSize.Width - reservedWidth, 0), textFlags);//用指定宽度测量文本面积 808 | wellSize = Convert.ToSingle(size.Width) / size.Height > PreferredScale //过于宽扁的情况 809 | ? Size.Ceiling(GetSameSizeWithNewScale(size, PreferredScale)) 810 | : size; 811 | 812 | //凑齐整行高,确保尾行显示 813 | int lineHeight = TextRenderer.MeasureText(" ", this.Font, new Size(int.MaxValue, 0), textFlags).Height;//单行高,Font.Height不靠谱 814 | int differ; 815 | wellSize.Height += (differ = wellSize.Height % lineHeight) == 0 ? 0 : (lineHeight - differ); 816 | } 817 | if (this.Icon != null) 818 | { 819 | wellSize.Width += this.Icon.Width + IconSpace; 820 | wellSize.Height = Math.Max(this.Icon.Height, wellSize.Height); 821 | } 822 | wellSize += Padding.Size; 823 | 824 | //不应超过指定尺寸。宽度在上面已确保不会超过 825 | if (wellSize.Height > proposedSize.Height) { wellSize.Height = proposedSize.Height; } 826 | 827 | return wellSize; 828 | } 829 | 830 | /// 831 | /// 重绘 832 | /// 833 | protected override void OnPaint(PaintEventArgs e) 834 | { 835 | Graphics g = e.Graphics; 836 | Rectangle rect = GetPaddedRectangle(); 837 | 838 | //绘制图标 839 | if (this.Icon != null) 840 | { 841 | g.DrawIcon(this.Icon, Padding.Left, Padding.Top); 842 | 843 | //右移文本区 844 | rect.X += this.Icon.Width + IconSpace; 845 | rect.Width -= this.Icon.Width + IconSpace; 846 | 847 | //若文字太少,则与图标垂直居中 848 | if (this.Text.Length < 100) 849 | { 850 | Size textSize = TextRenderer.MeasureText(g, this.Text, this.Font, rect.Size, textFlags); 851 | if (textSize.Height <= this.Icon.Height) 852 | { 853 | rect.Y += (this.Icon.Height - textSize.Height) / 2; 854 | } 855 | } 856 | } 857 | 858 | //g.FillRectangle(Brushes.Gainsboro, rect);//test 859 | 860 | //绘制文本 861 | TextRenderer.DrawText(g, this.Text, this.Font, rect, Color.Black, textFlags); 862 | 863 | base.OnPaint(e); 864 | } 865 | 866 | /// 867 | /// 根据原尺寸,得到相同面积、且指定比例的新尺寸 868 | /// 869 | /// 原尺寸 870 | /// 新尺寸比例。需是width/height 871 | private static SizeF GetSameSizeWithNewScale(Size src, float scale) 872 | { 873 | int sqr = src.Width * src.Height;//原面积 874 | double w = Math.Sqrt(sqr * scale);//新面积宽 875 | return new SizeF(Convert.ToSingle(w), Convert.ToSingle(sqr / w)); 876 | } 877 | 878 | /// 879 | /// 获取刨去Padding的内容区 880 | /// 881 | private Rectangle GetPaddedRectangle() 882 | { 883 | Rectangle r = this.ClientRectangle; 884 | r.X += this.Padding.Left; 885 | r.Y += this.Padding.Top; 886 | r.Width -= this.Padding.Horizontal; 887 | r.Height -= this.Padding.Vertical; 888 | return r; 889 | } 890 | } 891 | 892 | /// 893 | /// 屏蔽全选消息的文本框 894 | /// 895 | private class TextBoxUnSelectAllable : TextBox 896 | { 897 | protected override void WndProc(ref Message m) 898 | { 899 | //EM_SETSEL 900 | if (m.Msg == 0xB1) { return; } 901 | 902 | base.WndProc(ref m); 903 | } 904 | } 905 | 906 | /// 907 | /// 包装ToolBarButton为单一控件 908 | /// 909 | private class ToggleButton : Control 910 | { 911 | /// 912 | /// 展开/收起图标数据 913 | /// 914 | const string ImgDataBase64 = 915 | @"iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ 916 | bWFnZVJlYWR5ccllPAAAA3NJREFUeNqklVlPFEEQx/8zPccue6gorMd6gBegeCAQD4w+oCx+AInx 917 | IB4EfTK8+g2MQUUTcBU8En0wmvigEkyMxgcTjRrUqHFVUBRQQaJGl2WPmbG6dzCLWUiESf7T0739 918 | 666urqqVDjVcxT9PAWkfqZKUY491ktpIzaRXGPv5L15J+dZIRx26dqAwf56c48+Cx+1CzDDR//13 919 | /seevvx3HZ8OxmLxMzSvjhT5Z+Nx8UoKfHOu31e+qWwZPBkOMBkwTAvRuAE21QuvJwNz5s6U25++ 920 | rv365dtC+4SxifJsfeVWvsCJ2TOzqyo2FsHt1OBSFeiqTItIsOhHw7JgGBZM+s72TcOvX+GccHgw 921 | k7qttgHj5slOLNE0tXZNSQGYJEEhiDEJusLoW4ZMfZnGJVv0QmHhYuiaup+zE+W5Aftyc/xMURRh 922 | acJIKpowqDVhkhu5LCspiY6k0OIL5s9mdrCNyp9sDKL+6PExeW5AwOebigRNiiVMkoFIPIFwlLcG 923 | huIm4mRI3DRpAQg38oPMmD6Nuz4wGn+koRGH64/hxr1HuHjl2qg8D8JcZ4ZTRCtLSDjT1Ijz51rS 924 | 5lfVzj2o2rWXXCzDPcnNh3L5K5WntdHYdAqng6cwa/EK+AuK8SDUSx65gUAlxR1ZkcqLLDBpkJ+S 925 | R8yOvbXw+vx4GOoZsXlZyQqsK10pNlDpjlVZDPMs0FL55mATLl04C39+EWblFf3l2zs+w7jZii1b 926 | Kkfw3IDOcDiS5/G4yLjknQcCAbrPW3j8plvMWlu8XGwOsblMASYjFh3i3S4SS+W3Vddg++6apJ8t 927 | OwN4HHH/p+G5AW3f+gbyvB632DwGHigSyjdvpn4b9ElZWF9aJE6uMAanJsOlK3jdNcAXuE2y0vEQ 928 | rcXfyeCT0vPcES0funoNRTJpgixSRUQsLbapogIbVq8S47rKCORShQvbX7437NI6Km8Ol9sxeG7A 929 | i2g0Fnz2PAQ3TcjQGBw02UGWOqig8L7bweB1qCSFxHD3/nMMDkWDnJ0oP1yK6z529y1i8ovydaVL 930 | wXOaXxl3W7K4yKKykY/Rdq8dofe9d+x6jonyw6WYu+Pyj5/hzLedPcU61dDJLh1T3E4BRgYjCHV0 931 | 4/qdJ+bn/h+naW41KZpiwLh5Kc3fMS+vNXaRybVT7YMdcM2228d6/ov/I8AAPfkI7yO+mM8AAAAA 932 | SUVORK5CYII="; 933 | 934 | readonly bool isToggleMode; 935 | bool isChecked; 936 | bool useAnimate; 937 | readonly ImageList imgList; 938 | 939 | /// 940 | /// Checked改变后 941 | /// 942 | public event EventHandler CheckedChanged; 943 | 944 | /// 945 | /// 使用动画按钮效果 946 | /// 947 | private bool UseAnimate 948 | { 949 | get { return useAnimate; } 950 | set 951 | { 952 | if (useAnimate == value) { return; } 953 | 954 | useAnimate = value; 955 | if (IsHandleCreated) { this.CreateHandle(); } 956 | } 957 | } 958 | 959 | /// 960 | /// 获取或设置按钮是否处于按下状态 961 | /// 962 | [Description("获取或设置按钮是否处于按下状态"), DefaultValue(false)] 963 | public bool Checked 964 | { 965 | get 966 | { 967 | if (IsHandleCreated) 968 | { 969 | //保证isChecked与实情吻合。TB_ISBUTTONCHECKED 970 | isChecked = Convert.ToBoolean(SendMessage(this.Handle, 0x40A, IntPtr.Zero, IntPtr.Zero).ToInt32()); 971 | } 972 | return isChecked; 973 | } 974 | set 975 | { 976 | if (isChecked == value || !isToggleMode) { return; } 977 | 978 | isChecked = value; 979 | 980 | if (IsHandleCreated) 981 | { 982 | //TB_CHECKBUTTON 983 | SendMessage(this.Handle, 0x402, IntPtr.Zero, new IntPtr(Convert.ToInt32(value))); 984 | } 985 | 986 | OnCheckedChanged(EventArgs.Empty); 987 | } 988 | } 989 | 990 | /// 991 | /// 创建ToolBarButtonControl 992 | /// 993 | public ToggleButton(bool useAnimate) 994 | { 995 | SetStyle(ControlStyles.UserPaint, false); 996 | SetStyle(ControlStyles.AllPaintingInWmPaint, true); 997 | SetStyle(ControlStyles.OptimizedDoubleBuffer, true); 998 | SetStyle(ControlStyles.ResizeRedraw, true); 999 | 1000 | this.isToggleMode = true;//写死好了,独立版才提供设置 1001 | this.UseAnimate = useAnimate; 1002 | 1003 | //将图标加入imageList 1004 | imgList = new ImageList { ImageSize = new System.Drawing.Size(16, 16), ColorDepth = ColorDepth.Depth32Bit }; 1005 | using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(ImgDataBase64))) 1006 | { 1007 | imgList.Images.AddStrip(Image.FromStream(ms)); 1008 | } 1009 | } 1010 | 1011 | /// 1012 | /// 执行左键单击 1013 | /// 1014 | public void PerformClick() 1015 | { 1016 | SendMessage(this.Handle, 0x201, new IntPtr(0x1), IntPtr.Zero);//WM_LBUTTONDOWN 1017 | Application.DoEvents(); 1018 | SendMessage(this.Handle, 0x202, IntPtr.Zero, IntPtr.Zero); //WM_LBUTTONUP 1019 | } 1020 | 1021 | protected override void WndProc(ref Message m) 1022 | { 1023 | //忽略鼠标双击消息,WM_LBUTTONDBLCLK 1024 | if (m.Msg == 0x203) { return; } 1025 | 1026 | //有节操的响应鼠标动作 1027 | if ((m.Msg == 0x201 || m.Msg == 0x202) && (!this.Enabled || !this.Visible)) 1028 | { 1029 | return; 1030 | } 1031 | base.WndProc(ref m); 1032 | } 1033 | 1034 | //创建ToolBar 1035 | protected override CreateParams CreateParams 1036 | { 1037 | get 1038 | { 1039 | CreateParams prms = base.CreateParams; 1040 | prms.ClassName = "ToolbarWindow32"; 1041 | prms.Style = 0x40000000 1042 | | 0x10000000 1043 | //| 0x2000000 //WS_CLIPCHILDREN 1044 | //| 0x8000 1045 | | 0x1 1046 | | 0x4 1047 | | 0x8 1048 | | 0x40 1049 | | 0x1000 //TBSTYLE_LIST,图标文本横排 1050 | ; 1051 | if (UseAnimate) { prms.Style |= 0x800; }//TBSTYLE_FLAT。flat模式在NT6.x下,按钮按下会有动画效果 1052 | 1053 | prms.ExStyle = 0; 1054 | 1055 | return prms; 1056 | } 1057 | } 1058 | 1059 | protected override void OnHandleCreated(EventArgs e) 1060 | { 1061 | base.OnHandleCreated(e); 1062 | 1063 | //设置imgList 1064 | SendMessage(this.Handle, 0x430, IntPtr.Zero, imgList.Handle);//TB_SETIMAGELIST 1065 | 1066 | //准备添加按钮 1067 | int btnStructSize = Marshal.SizeOf(typeof(TBBUTTON)); 1068 | SendMessage(this.Handle, 0x41E, new IntPtr(btnStructSize), IntPtr.Zero);//TB_BUTTONSTRUCTSIZE,必须在添加按钮前 1069 | 1070 | //构建按钮信息 1071 | TBBUTTON btnStruct = new TBBUTTON 1072 | { 1073 | //iBitmap = 0, 1074 | //idCommand = 0, 1075 | fsState = 0x4, //TBSTATE_ENABLED 1076 | iString = SendMessage(this.Handle, 0x44D, 0, this.Text + '\0')//TB_ADDSTRING 1077 | }; 1078 | if (this.isToggleMode) { btnStruct.fsStyle = 0x2; }//BTNS_CHECK。作为切换按钮时 1079 | 1080 | IntPtr btnStructStart = IntPtr.Zero; 1081 | try 1082 | { 1083 | btnStructStart = Marshal.AllocHGlobal(btnStructSize);//在非托管区创建一个指针 1084 | Marshal.StructureToPtr(btnStruct, btnStructStart, true);//把结构体塞到上述指针 1085 | 1086 | //添加按钮 1087 | SendMessage(this.Handle, 0x444, new IntPtr(1)/*按钮数量*/, btnStructStart);//TB_ADDBUTTONS。从指针取按钮信息 1088 | 1089 | //设置按钮尺寸刚好为ToolBar尺寸 1090 | AdjustButtonSize(); 1091 | } 1092 | finally 1093 | { 1094 | if (btnStructStart != IntPtr.Zero) { Marshal.FreeHGlobal(btnStructStart); } 1095 | } 1096 | } 1097 | 1098 | protected override bool ProcessCmdKey(ref Message m, Keys keyData) 1099 | { 1100 | //将空格和回车作为鼠标单击处理 1101 | if (m.Msg == 0x100 && (keyData == Keys.Enter || keyData == Keys.Space)) 1102 | { 1103 | PerformClick(); 1104 | return true; 1105 | } 1106 | 1107 | return base.ProcessCmdKey(ref m, keyData); 1108 | } 1109 | 1110 | /// 1111 | /// 处理助记键 1112 | /// 1113 | protected override bool ProcessMnemonic(char charCode) 1114 | { 1115 | if (IsMnemonic(charCode, this.Text)) 1116 | { 1117 | PerformClick(); 1118 | return true; 1119 | } 1120 | 1121 | return base.ProcessMnemonic(charCode); 1122 | } 1123 | 1124 | protected override void OnClick(EventArgs e) 1125 | { 1126 | //忽略鼠标右键 1127 | MouseEventArgs me = e as MouseEventArgs; 1128 | if (me != null && me.Button != System.Windows.Forms.MouseButtons.Left) 1129 | { return; } 1130 | 1131 | //若是切换模式,直接引发Checked事件(不要通过设置Checked属性引发,因为OnClick发送之前就已经Check了) 1132 | //存在理论上的不可靠,但暂无更好办法 1133 | if (isToggleMode) 1134 | { this.OnCheckedChanged(EventArgs.Empty); } 1135 | 1136 | base.OnClick(e); 1137 | } 1138 | 1139 | //重绘后重设按钮尺寸 1140 | protected override void OnInvalidated(InvalidateEventArgs e) 1141 | { 1142 | base.OnInvalidated(e); 1143 | AdjustButtonSize(); 1144 | } 1145 | 1146 | /// 1147 | /// 引发CheckedChanged事件 1148 | /// 1149 | protected virtual void OnCheckedChanged(EventArgs e) 1150 | { 1151 | SetImageIndex(this.Checked ? 1 : 0); 1152 | 1153 | if (CheckedChanged != null) { CheckedChanged(this, e); } 1154 | } 1155 | 1156 | /// 1157 | /// 设置图标索引 1158 | /// 1159 | private void SetImageIndex(int index) 1160 | { 1161 | //TB_CHANGEBITMAP 1162 | SendMessage(this.Handle, 0x42B, IntPtr.Zero, new IntPtr(index)); 1163 | } 1164 | 1165 | /// 1166 | /// 调整按钮尺寸刚好为ToolBar尺寸 1167 | /// 1168 | private void AdjustButtonSize() 1169 | { 1170 | IntPtr lParam = new IntPtr((this.Width & 0xFFFF) | (this.Height << 0x10)); //MakeLParam手法 1171 | SendMessage(this.Handle, 0x41F, IntPtr.Zero, lParam); //TB_SETBUTTONSIZE 1172 | } 1173 | 1174 | #region Win32 API 1175 | 1176 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 1177 | private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 1178 | 1179 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 1180 | private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, string lParam); 1181 | 1182 | [StructLayout(LayoutKind.Sequential)] 1183 | private struct TBBUTTON 1184 | { 1185 | public int iBitmap; 1186 | public int idCommand; 1187 | public byte fsState; 1188 | public byte fsStyle; 1189 | public byte bReserved0; 1190 | public byte bReserved1; 1191 | public IntPtr dwData; 1192 | public IntPtr iString; 1193 | } 1194 | 1195 | #endregion 1196 | } 1197 | 1198 | #endregion 1199 | } 1200 | } 1201 | } 1202 | -------------------------------------------------------------------------------- /CustomControls/RadioGroupBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace AhDung.WinForm.Controls 6 | { 7 | /// 8 | /// 单选组面板 9 | /// 10 | [ToolboxItem(true)] 11 | public class RadioGroupBox : CheckableGroupBox, IRadioControl 12 | { 13 | Control _lastParent; 14 | 15 | /// 16 | /// 初始化本类 17 | /// 18 | public RadioGroupBox() 19 | : base(false) 20 | { 21 | this.ParentChanged += RadioGroupBox_ParentChanged; 22 | } 23 | 24 | void RadioGroupBox_ParentChanged(object sender, EventArgs e) 25 | { 26 | if (_lastParent != null) 27 | { 28 | foreach (Control c in _lastParent.Controls) 29 | { 30 | if (c is RadioButton) 31 | { 32 | ((RadioButton)c).CheckedChanged -= RadioGroupBox_CheckedChanged; 33 | } 34 | } 35 | _lastParent.ControlAdded -= Parent_ControlAdded; 36 | _lastParent.ControlRemoved -= Parent_ControlRemoved; 37 | } 38 | _lastParent = Parent; 39 | if (_lastParent != null) 40 | { 41 | foreach (Control c in _lastParent.Controls) 42 | { 43 | if (c is RadioButton) 44 | { 45 | ((RadioButton)c).CheckedChanged += RadioGroupBox_CheckedChanged; 46 | } 47 | } 48 | _lastParent.ControlAdded += Parent_ControlAdded; 49 | _lastParent.ControlRemoved += Parent_ControlRemoved; 50 | } 51 | } 52 | 53 | void RadioGroupBox_CheckedChanged(object sender, EventArgs e) 54 | { 55 | var rb = sender as RadioButton; 56 | if (rb.Checked) 57 | { 58 | this.Checked = false; 59 | } 60 | } 61 | 62 | void Parent_ControlAdded(object sender, ControlEventArgs e) 63 | { 64 | if (e.Control is RadioButton) 65 | { 66 | ((RadioButton)e.Control).CheckedChanged += RadioGroupBox_CheckedChanged; 67 | } 68 | } 69 | 70 | void Parent_ControlRemoved(object sender, ControlEventArgs e) 71 | { 72 | if (e.Control is RadioButton) 73 | { 74 | ((RadioButton)e.Control).CheckedChanged -= RadioGroupBox_CheckedChanged; 75 | } 76 | } 77 | 78 | protected override void OnCheckedChanged(EventArgs e) 79 | { 80 | //互斥。 81 | if (this.Checked && this.Parent != null) 82 | { 83 | foreach (Control c in this.Parent.Controls) 84 | { 85 | if (c == this) { continue; } 86 | 87 | if (c is RadioButton) 88 | { 89 | ((RadioButton)c).Checked = false; 90 | } 91 | else if (c is IRadioControl) 92 | { 93 | ((IRadioControl)c).Checked = false; 94 | } 95 | } 96 | } 97 | base.OnCheckedChanged(e); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /DialogDragger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace AhDung.WinForm 8 | { 9 | //todo 颜色对话框有问题,禁止使用 10 | /// 11 | /// 对话框拖拽器 12 | /// 13 | [Obsolete("尚有严重问题,禁用", true)] 14 | internal static class DialogDragger 15 | { 16 | private static bool CanDrag(IntPtr hWnd)//, POINT pt) 17 | { 18 | var name = GetClassName(hWnd); 19 | switch (name) 20 | { 21 | case "SysTabControl32": 22 | case "msctls_progress32": 23 | case "msctls_statusbar32": 24 | return true; 25 | 26 | case "Static": 27 | return !HasStyle(hWnd, 0xB/*SS_SIMPLE*/); 28 | 29 | case "Button": 30 | return HasStyle(hWnd, 7/*BS_GROUPBOX*/); 31 | } 32 | return false; 33 | } 34 | 35 | /// 36 | /// 钩子消息处理过程 37 | /// 38 | private static IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam) 39 | { 40 | if (nCode == 0/*MSGF_DIALOGBOX*/) 41 | { 42 | var m = (MSG)Marshal.PtrToStructure(lParam, typeof(MSG)); 43 | switch (m.Msg) 44 | { 45 | case 0x201: 46 | //todo 颜色对话框中的色块点击时得到的句柄是窗体本身,暂时没办法处理 47 | if ((int)m.wParam != 1) { break; } 48 | if (GetClassName(m.hWnd) == "ComboLBox") { break; } 49 | 50 | var hForm = GetAncestor(m.hWnd, 2/*GA_ROOT*/); 51 | if (m.hWnd == hForm || CanDrag(m.hWnd)) 52 | { 53 | SendMessage(hForm, 0xA1, (IntPtr)2, IntPtr.Zero); 54 | return (IntPtr)1; 55 | } 56 | break; 57 | } 58 | } 59 | return CallNextHookEx(_hHook, nCode, wParam, lParam); 60 | } 61 | 62 | 63 | static IntPtr _hHook; 64 | static HookProcDelegate _proc = HookProc; 65 | 66 | /// 67 | /// 安装钩子。不能重复安装 68 | /// 69 | /// 70 | /// 71 | private static void Install() 72 | { 73 | if (_hHook != IntPtr.Zero) 74 | { 75 | throw new InvalidOperationException(); 76 | } 77 | // ReSharper disable once CSharpWarnings::CS0618 78 | _hHook = SetWindowsHookEx(-1/*WH_MSGFILTER*/, _proc, IntPtr.Zero, AppDomain.GetCurrentThreadId()); 79 | if (_hHook == IntPtr.Zero) 80 | { 81 | throw new Win32Exception(); 82 | } 83 | } 84 | 85 | /// 86 | /// 卸载钩子 87 | /// 88 | /// 89 | private static void UnInstall() 90 | { 91 | if (_hHook == IntPtr.Zero) 92 | { 93 | return; 94 | } 95 | if (UnhookWindowsHookEx(_hHook)) 96 | { 97 | _hHook = IntPtr.Zero; 98 | } 99 | else 100 | { 101 | throw new Win32Exception(); 102 | } 103 | } 104 | 105 | [StructLayout(LayoutKind.Sequential)] 106 | private struct MSG 107 | { 108 | public IntPtr hWnd; 109 | public int Msg; 110 | public IntPtr wParam; 111 | public IntPtr lParam; 112 | public int time; 113 | public POINT pt; 114 | } 115 | 116 | delegate IntPtr HookProcDelegate(int nCode, IntPtr wParam, IntPtr lParam); 117 | 118 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 119 | private static extern bool UnhookWindowsHookEx(IntPtr hhk); 120 | 121 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 122 | private static extern IntPtr SetWindowsHookEx(int idHook, HookProcDelegate lpfn, IntPtr hMod, int dwThreadId); 123 | 124 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 125 | private static extern IntPtr CallNextHookEx(IntPtr hhook, int code, IntPtr wparam, IntPtr lparam); 126 | 127 | 128 | /// 129 | /// 检查窗口是否含有指定样式 130 | /// 131 | private static bool HasStyle(IntPtr hWnd, int style, bool isExStyle = false) 132 | { 133 | var s = unchecked((int)(long)GetWindowLong(hWnd, isExStyle 134 | ? -20/*GWL_EXSTYLE*/ 135 | : -16/*GWL_STYLE*/)); 136 | return (s & style) == style; 137 | } 138 | 139 | private static IntPtr GetWindowLong(IntPtr hWnd, int nIndex) 140 | { 141 | if (IntPtr.Size == 4) 142 | { 143 | return GetWindowLong32(hWnd, nIndex); 144 | } 145 | return GetWindowLongPtr64(hWnd, nIndex); 146 | } 147 | 148 | [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowLong")] 149 | private static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex); 150 | 151 | [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowLongPtr")] 152 | private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex); 153 | 154 | /// 155 | /// 获取窗口类名 156 | /// 157 | private static string GetClassName(IntPtr hWnd) 158 | { 159 | var sb = new StringBuilder(255); 160 | if (GetClassName(hWnd, sb, sb.Capacity) == 0) 161 | { 162 | throw new Win32Exception(); 163 | } 164 | return sb.ToString(); 165 | } 166 | 167 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 168 | private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 169 | 170 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 171 | private static extern IntPtr GetAncestor(IntPtr hWnd, int flags); 172 | 173 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 174 | private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 175 | 176 | [StructLayout(LayoutKind.Sequential)] 177 | private struct POINT 178 | { 179 | public int X; 180 | public int Y; 181 | 182 | public static explicit operator POINT(Point pt) 183 | { 184 | return new POINT { X = pt.X, Y = pt.Y }; 185 | } 186 | 187 | public static explicit operator Point(POINT pt) 188 | { 189 | return new Point(pt.X, pt.Y); 190 | } 191 | 192 | public override string ToString() 193 | { 194 | return X + ", " + Y; 195 | } 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /FmMDI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Windows.Forms; 4 | using AhDung.WinForm; 5 | 6 | namespace AhDung 7 | { 8 | public partial class FmMDI : Form 9 | { 10 | public FmMDI() 11 | { 12 | InitializeComponent(); 13 | 14 | FormDragger.Dragging += FormDragger_Dragging; 15 | FormDragger.EnabledChanged += FormDragger_EnabledChanged; 16 | 17 | //例外方式一:将控件添加进例外列表 18 | //FormDragger.ExcludeControls.Add(pictureBox1); 19 | } 20 | 21 | void FormDragger_Dragging(object sender, FormDraggingCancelEventArgs e) 22 | { 23 | //例外方式二:在FormDragging事件中令Cancel = true 24 | //if (e.Control == pictureBox1) 25 | //{ 26 | // e.Cancel = true; 27 | //} 28 | statusBarPanel1.Text = string.Format("{0}, {1}:{2}", 29 | e.Control.GetType().Name, e.IsClientArea ? "客户区坐标" : "屏幕坐标", e.MousePosition); 30 | } 31 | 32 | //图片点击事件。仅当该控件处于例外或关闭整个拖拽器时会触发 33 | private void pictureBox1_MouseClick(object sender, MouseEventArgs e) 34 | { 35 | VisitAuthorHome(); 36 | } 37 | 38 | private void checkBox1_CheckedChanged(object sender, EventArgs e) 39 | { 40 | //拖拽器开关 41 | FormDragger.Enabled = toolStripCheckBox1.Checked; 42 | } 43 | 44 | void FormDragger_EnabledChanged(object sender, EventArgs e) 45 | { 46 | //放心这里不会造成来回触发,因为Enabled内部有重入处理 47 | if (FormDragger.Enabled) 48 | { 49 | toolStripCheckBox1.Checked = true; 50 | toolStripCheckBox1.Text = "拖拽:开"; 51 | } 52 | else 53 | { 54 | toolStripCheckBox1.Checked = false; 55 | toolStripCheckBox1.Text = "拖拽:关"; 56 | } 57 | } 58 | 59 | private void FmMDI_Load(object sender, EventArgs e) 60 | { 61 | linkLabel1.Links.Add(2, 5, "AAA"); 62 | linkLabel1.Links.Add(8, 6, "BBB").Enabled = false; 63 | 64 | treeView1.ExpandAll(); 65 | 66 | this.ContextMenu = contextMenu1; 67 | } 68 | 69 | private void VisitAuthorHome() 70 | { 71 | Process.Start("http://www.cnblogs.com/ahdung/p/FormDragger.html"); 72 | } 73 | 74 | private void btnAbout_Click(object sender, EventArgs e) 75 | { 76 | VisitAuthorHome(); 77 | } 78 | 79 | private void newChild_Click(object sender, EventArgs e) 80 | { 81 | new FmTestDrag { MdiParent = this }.Show(); 82 | } 83 | 84 | private void newNormal_Click(object sender, EventArgs e) 85 | { 86 | new FmTestDrag().Show(); 87 | } 88 | 89 | private void newModal_Click(object sender, EventArgs e) 90 | { 91 | new FmTestDrag().ShowDialog(); 92 | } 93 | 94 | //private void btnShowMsgBox_Click(object sender, EventArgs e) 95 | //{ 96 | // MessageBox.Show("拖我试试"); 97 | //} 98 | 99 | //private void miOpenFileDialog_Click(object sender, EventArgs e) 100 | //{ 101 | // new OpenFileDialog().ShowDialog(); 102 | //} 103 | 104 | //private void miSaveFileDialog_Click(object sender, EventArgs e) 105 | //{ 106 | // new SaveFileDialog().ShowDialog(); 107 | //} 108 | 109 | //private void miFolderBrowserDialog_Click(object sender, EventArgs e) 110 | //{ 111 | // new FolderBrowserDialog().ShowDialog(); 112 | //} 113 | 114 | //private void miColorDialog_Click(object sender, EventArgs e) 115 | //{ 116 | // new ColorDialog().ShowDialog(); 117 | //} 118 | 119 | //private void miFontDialog_Click(object sender, EventArgs e) 120 | //{ 121 | // new FontDialog().ShowDialog(); 122 | //} 123 | 124 | //private void miPageSetupDialog_Click(object sender, EventArgs e) 125 | //{ 126 | // new PageSetupDialog() { Document = new PrintDocument() }.ShowDialog(); 127 | //} 128 | 129 | //private void miPrintDialog_Click(object sender, EventArgs e) 130 | //{ 131 | // //todo 勾不到 132 | // new PrintDialog() { UseEXDialog = true }.ShowDialog(); 133 | //} 134 | 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /FmTabMDI.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace AhDung 2 | { 3 | partial class FmTabMDI 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.tabControl1 = new System.Windows.Forms.TabControl(); 32 | this.tabPage1 = new System.Windows.Forms.TabPage(); 33 | this.tabPage2 = new System.Windows.Forms.TabPage(); 34 | this.button1 = new System.Windows.Forms.Button(); 35 | this.tabControl1.SuspendLayout(); 36 | this.SuspendLayout(); 37 | // 38 | // tabControl1 39 | // 40 | this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 41 | | System.Windows.Forms.AnchorStyles.Left) 42 | | System.Windows.Forms.AnchorStyles.Right))); 43 | this.tabControl1.Controls.Add(this.tabPage1); 44 | this.tabControl1.Controls.Add(this.tabPage2); 45 | this.tabControl1.Location = new System.Drawing.Point(12, 71); 46 | this.tabControl1.Name = "tabControl1"; 47 | this.tabControl1.SelectedIndex = 0; 48 | this.tabControl1.Size = new System.Drawing.Size(776, 367); 49 | this.tabControl1.TabIndex = 0; 50 | // 51 | // tabPage1 52 | // 53 | this.tabPage1.Location = new System.Drawing.Point(4, 22); 54 | this.tabPage1.Name = "tabPage1"; 55 | this.tabPage1.Padding = new System.Windows.Forms.Padding(3); 56 | this.tabPage1.Size = new System.Drawing.Size(768, 341); 57 | this.tabPage1.TabIndex = 0; 58 | this.tabPage1.Text = "tabPage1"; 59 | this.tabPage1.UseVisualStyleBackColor = true; 60 | // 61 | // tabPage2 62 | // 63 | this.tabPage2.Location = new System.Drawing.Point(4, 22); 64 | this.tabPage2.Name = "tabPage2"; 65 | this.tabPage2.Padding = new System.Windows.Forms.Padding(3); 66 | this.tabPage2.Size = new System.Drawing.Size(192, 74); 67 | this.tabPage2.TabIndex = 1; 68 | this.tabPage2.Text = "tabPage2"; 69 | this.tabPage2.UseVisualStyleBackColor = true; 70 | // 71 | // button1 72 | // 73 | this.button1.Location = new System.Drawing.Point(16, 12); 74 | this.button1.Name = "button1"; 75 | this.button1.Size = new System.Drawing.Size(163, 23); 76 | this.button1.TabIndex = 1; 77 | this.button1.Text = "ShowCustomMessageBox"; 78 | this.button1.UseVisualStyleBackColor = true; 79 | this.button1.Click += new System.EventHandler(this.button1_Click); 80 | // 81 | // FmTabMDI 82 | // 83 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 84 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 85 | this.ClientSize = new System.Drawing.Size(800, 450); 86 | this.Controls.Add(this.button1); 87 | this.Controls.Add(this.tabControl1); 88 | this.Name = "FmTabMDI"; 89 | this.Text = "FmTabMDI"; 90 | this.Load += new System.EventHandler(this.FmTabMDI_Load); 91 | this.tabControl1.ResumeLayout(false); 92 | this.ResumeLayout(false); 93 | 94 | } 95 | 96 | #endregion 97 | 98 | private System.Windows.Forms.TabControl tabControl1; 99 | private System.Windows.Forms.TabPage tabPage1; 100 | private System.Windows.Forms.TabPage tabPage2; 101 | private System.Windows.Forms.Button button1; 102 | } 103 | } -------------------------------------------------------------------------------- /FmTabMDI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using AhDung.WinForm; 4 | 5 | namespace AhDung 6 | { 7 | public partial class FmTabMDI : Form 8 | { 9 | public FmTabMDI() 10 | { 11 | InitializeComponent(); 12 | } 13 | 14 | private void button1_Click(object sender, EventArgs e) 15 | { 16 | var form = tabControl1.SelectedTab.Controls[0]; 17 | MessageBoxEx.Show(form.GetType().ToString(), "Custom message box", "attach message"); 18 | } 19 | 20 | private void FmTabMDI_Load(object sender, EventArgs e) 21 | { 22 | foreach (TabPage page in tabControl1.TabPages) 23 | { 24 | page.Controls.Add(new FmTabSub { TopLevel = false, Dock = DockStyle.Fill, FormBorderStyle = FormBorderStyle.None, Visible = true }); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FmTabMDI.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /FmTabSub.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace AhDung 2 | { 3 | partial class FmTabSub 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.label1 = new System.Windows.Forms.Label(); 32 | this.button1 = new System.Windows.Forms.Button(); 33 | this.SuspendLayout(); 34 | // 35 | // label1 36 | // 37 | this.label1.AutoSize = true; 38 | this.label1.Location = new System.Drawing.Point(85, 57); 39 | this.label1.Name = "label1"; 40 | this.label1.Size = new System.Drawing.Size(155, 12); 41 | this.label1.TabIndex = 0; 42 | this.label1.Text = "This is a Form in TabPage"; 43 | // 44 | // button1 45 | // 46 | this.button1.Location = new System.Drawing.Point(87, 145); 47 | this.button1.Name = "button1"; 48 | this.button1.Size = new System.Drawing.Size(75, 23); 49 | this.button1.TabIndex = 1; 50 | this.button1.Text = "button1"; 51 | this.button1.UseVisualStyleBackColor = true; 52 | this.button1.Click += new System.EventHandler(this.button1_Click); 53 | // 54 | // FmTabSub 55 | // 56 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 57 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 58 | this.ClientSize = new System.Drawing.Size(537, 374); 59 | this.Controls.Add(this.button1); 60 | this.Controls.Add(this.label1); 61 | this.Name = "FmTabSub"; 62 | this.Text = "FmTabSub"; 63 | this.ResumeLayout(false); 64 | this.PerformLayout(); 65 | 66 | } 67 | 68 | #endregion 69 | 70 | private System.Windows.Forms.Label label1; 71 | private System.Windows.Forms.Button button1; 72 | } 73 | } -------------------------------------------------------------------------------- /FmTabSub.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Windows.Forms; 8 | using AhDung.WinForm; 9 | 10 | namespace AhDung 11 | { 12 | public partial class FmTabSub : Form 13 | { 14 | public FmTabSub() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | private void button1_Click(object sender, EventArgs e) 20 | { 21 | DialogResult = DialogResult.OK; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /FmTabSub.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /FmTestDrag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Windows.Forms; 4 | using AhDung.WinForm; 5 | 6 | namespace AhDung 7 | { 8 | public partial class FmTestDrag : Form 9 | { 10 | public FmTestDrag() 11 | { 12 | InitializeComponent(); 13 | 14 | FormDragger.Dragging += FormDragger_Dragging; 15 | FormDragger.EnabledChanged += FormDragger_EnabledChanged; 16 | 17 | //例外方式一:将控件添加进例外列表 18 | //FormDragger.ExcludeControls.Add(pictureBox1); 19 | } 20 | 21 | void FormDragger_Dragging(object sender, FormDraggingCancelEventArgs e) 22 | { 23 | //例外方式二:在FormDragging事件中令Cancel = true 24 | //if (e.Control == pictureBox1) 25 | //{ 26 | // e.Cancel = true; 27 | //} 28 | statusBarPanel1.Text = string.Format("{0}, {1}:{2}", 29 | e.Control.GetType().Name, e.IsClientArea ? "客户区坐标" : "屏幕坐标", e.MousePosition); 30 | } 31 | 32 | //图片点击事件。仅当该控件处于例外或关闭整个拖拽器时会触发 33 | private void pictureBox1_MouseClick(object sender, MouseEventArgs e) 34 | { 35 | VisitAuthorHome(); 36 | } 37 | 38 | private void checkBox1_CheckedChanged(object sender, EventArgs e) 39 | { 40 | //拖拽器开关 41 | FormDragger.Enabled = toolStripCheckBox1.Checked; 42 | } 43 | 44 | void FormDragger_EnabledChanged(object sender, EventArgs e) 45 | { 46 | //放心这里不会造成来回触发,因为Enabled内部有重入处理 47 | if (FormDragger.Enabled) 48 | { 49 | toolStripCheckBox1.Checked = true; 50 | toolStripCheckBox1.Text = "拖拽:开"; 51 | } 52 | else 53 | { 54 | toolStripCheckBox1.Checked = false; 55 | toolStripCheckBox1.Text = "拖拽:关"; 56 | } 57 | } 58 | 59 | private void FmMDI_Load(object sender, EventArgs e) 60 | { 61 | linkLabel1.Links.Add(2, 5, "AAA"); 62 | linkLabel1.Links.Add(8, 6, "BBB").Enabled = false; 63 | 64 | treeView1.ExpandAll(); 65 | 66 | this.ContextMenu = contextMenu1; 67 | } 68 | 69 | private void VisitAuthorHome() 70 | { 71 | Process.Start("http://www.cnblogs.com/ahdung/p/FormDragger.html"); 72 | } 73 | 74 | private void btnAbout_Click(object sender, EventArgs e) 75 | { 76 | VisitAuthorHome(); 77 | } 78 | 79 | private void newNormal_Click(object sender, EventArgs e) 80 | { 81 | new FmTestDrag().Show(); 82 | } 83 | 84 | private void newModal_Click(object sender, EventArgs e) 85 | { 86 | new FmTestDrag().ShowDialog(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /FmTestDrag.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | 123 | /9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkK 124 | DA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQ 125 | EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCACkAeADASIAAhEBAxEB/8QA 126 | HwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIh 127 | MUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVW 128 | V1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG 129 | x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQF 130 | BgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV 131 | YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE 132 | hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq 133 | 8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5K/ak1NNcuNB12e2Ntdtbvp+o2pPz2lzE5Z0IxwAXLA9CBkcV 134 | 43cald6papoSsn2skiNhIFG07cA5xjIXP/Avavpr9pu08M+LNIh8R6Qim7tr6ayuJQu0sAJAVYdyGUMC 135 | eTkHocV8uQ+Htd1iZvsdpLdSRfKOSSpC5AHrgAflRCS5rHfVozk+ZGx4U0648QQnw99qjsooHe5e4kJI 136 | O07Qq+pwV/75PrXreg+EvBttIWubwzu0jShphtCkqFAAHYBQOa8It5b2NRaMHCgjgEjaMkkDnvkdfSrs 137 | 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 491 | t2lU4yjKWI/NQfxNfnhoZzKh/wBiiipgbdD/2Q== 492 | 493 | 494 | 495 | True 496 | 497 | 498 | True 499 | 500 | 501 | True 502 | 503 | 504 | 720, 17 505 | 506 | 507 | 508 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 509 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 510 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 511 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 512 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 513 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 514 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 515 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 516 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 517 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 518 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 519 | 520 | 521 | 522 | 523 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 524 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 525 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 526 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 527 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 528 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 529 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 530 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 531 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 532 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 533 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 534 | 535 | 536 | 537 | 610, 17 538 | 539 | 540 | 541 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 542 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAERSURBVDhPrZDbSgJRGIXnpewd6jXsjSQvIrwoI0RQMChU 543 | 0iiDPCGiE3ZCRkvR8VzTeBhnyR5/ccaZNnPhB4t9sdf6Ln5hb8QeathNJFVFKF5C8DqL4ksDVHWGDf7j 544 | LHyPg6NjviSaFqlu5yQYR+KpupaIkrMknCxT3Y7v/NYYb0ITK1c3BarbWWhLQ7IR0cTKReyZ6lZ0XYei 545 | ztHpK4bAc+h1FgQijzSxMptrGIxVSO0xX3AaStFki7bUMVFmaMm/eJMGfIH/MkGzLep0AXn4h/r3CJV3 546 | mS9gn2bY4UY/UzQ7E9TqfeTFtnuB+XAfzSHKr11kSl/uBebDiZ89ZCst3OUkdwL28sIVsE83ock+EIQV 547 | 2Mz2wxeg6/UAAAAASUVORK5CYII= 548 | 549 | 550 | 551 | 552 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 553 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIySURBVDhPrZLfS5NRGMfff6H7boIuuq2pMZyL1eAt11CW 554 | DcOKsB9vpFmaLtNExco0av6CbIVLJ61Wk3BSkT/AFCkRZSpZmrmiJQ41xSaCwdfznL15XEUX0Reem5f3 555 | 8znnec4j/Zc8fxYGla91CS3eRTx0z6OpMYS7jmnU1X6B/VYA18snUVoyjsKCt8jLHcH5c36ouCQR2NUJ 556 | 1Nas4G9ZXlmFKbULh1Kf8lJxSfI+WeCCyopv6q+/h+DQ/DJ2WV5Ao1FgPegRAveDOS4oLfmq/h6dn/DH 557 | 4AJizD4UXJrCAUuzEDgbZrjgou2DiohshIcnQtgme5GTPYbkJKcQ1N8OckHW2REVi+RXuM8fxGaDG4oy 558 | ALPZIQQ11Z+5QDk1oKJ/hjv7P2FTfCMOH3mFxMQ6IbhROYWOdrCnBI4dfwPr0V4+bRoY9UzXppMjcDdS 559 | rC8hy3YhuFI2gTYf2A4Aza4f7N2/o/zaLB8qDYx6zszwr8P7k1thNFYIweXCMXgeAfedq2xxwjClZUeV 560 | Jd2GtDNFETiJwfs8MBjKhMCWN8pgoLoqzE8miH1GjE7G4PsZjE7OQsm9ij2mFg7rdrug1xcJAa2l4w7W 561 | r00Cgk/n38S7wBwC04u4UGxHrMHF4CbEJtyDLj5fCDIzhljfSxzeavRgyw4Zj9t64GvvQ0d3P3pfD2Kv 562 | 2QqNvgFxDN6urYdWmyMElJMnevh60obRktA701PRtGlg1DOdSkXwzrisaMG/RZLWAE60OMW5fNhvAAAA 563 | AElFTkSuQmCC 564 | 565 | 566 | 567 | 568 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 569 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIpSURBVDhPtZL/T1JRGMb5p1itrVZbbRpqZbawnBENV1I0 570 | jGlByTSyJTXJwq2oKZQb1KAv6JCYWSxvBrkkZUq4CeQEiRABFeLL072Xa0zRra31bO8v57zP5znnPYf1 571 | X+TxhWF6O7VtGYcnwbSWijKPOLzYrPSvLPwLS3huGUMlT7o9wGD9grVUBj+icdid03S9tDmgNxNwTgVQ 572 | J+rA8XNtWwM+uuZATMwxmQVRycuJFNyzIRitDlScugKzjSgFRGJJaIwEsrk8AsHIhnSL/Ssck37UNipQ 573 | I5DjtuYV7uksRYhr2kebhx2eP6nrycFIEh5fBA/1Nvru8q5+PDaOovK0rABwfwugWzcErfkzHhjsePL6 574 | E7q1VrTdNUDcrgGvSYlDZHN5XTNOnL8BVe8AJAoNDtZfLgDu9L1BPJmikzcrk81hlRwodZJwdBXziwnI 575 | OrVoaOkiT8C8hKLHBPO7CbywOaE1jeC+bhAd6meQdvZC1KoG/5IS3MZ2HObLUHZSggvkWq3wOvbWiAqA 576 | VpWeyStVfCUNf3AZ4zNhfHCFMEDMgye+hYr6FrDLzxQAUuVTpr0ocn74mchg5vsKRt1RcHp2Qv9+kZ78 577 | UcE17KkWFgHNN/uQzgBkGKLJPBZiecyGchjzrmFwPIF++xJUbDbUQzEacIArLpopSRSP4CUN1Obf1Abz 578 | uqob5KjiXwWH/GVl5HPt5zZh37GL2H1EiF1VZ7GDI6CNW5r/TSzWbwHYL0mKJ5czAAAAAElFTkSuQmCC 579 | 580 | 581 | 582 | 583 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 584 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHkSURBVDhPvZHfS1NhHIf3p5QypLr2D4goMwoMCi/qIugH 585 | Xe1Cr7qKDIMkZixwNhfWLGWbnuki0kXKzLU023KubBNPJrbRdOzocm6e2dPOO21mMS+CHvjcvOf9PF++ 586 | 79H9M+7RT2iRRsIi9sEAXe43yAvf2LpSHq28G9uAnytNT4jMLewtcQ2Ht2pF8ps/aOt+gccX5lxD694S 587 | +1BQFD1RkN5DSFa4Z3uONKbgHE3h8KZ4OJTC1J8UiSzmfhd2uf1CoJHbyKOsZokl0kKwm+aeJaov+wjO 588 | rpQkVqdXfOz0bWAcVLghfaXxkUz3y2VxvpMGSwL3uMKh+gHezSSLEnNhX23vtYzKUirDfGyFj/Iy1mdx 589 | UWqR8iKhwtQLxjgH659y4EwvVXWPiwJt3/Ws+muywRrlqvkDdx3zQrCN8l1ldnEd3/QqFmkS/akHJYGS 590 | zjLzOUEwEsMf+sLI2zmaOou/93pPGoM5zvk7UU7fnBKxSBPoT7SXBNW1F/9Io2lKCNTCeomUyrS8xnBA 591 | wfUqyf1eP5U1ptJD/o1LzeNCsHPydtqdr6k4aiwvOHvNSya3ibU/QIdrEkvfhJislc32MfYfuV1eUGPw 592 | FF7bIVJVZ0N/soPK421UHGstlFvYd/hWecF/Qqf7CR0A5wwgSQA2AAAAAElFTkSuQmCC 593 | 594 | 595 | 596 | 597 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 598 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJSSURBVDhPtZJrSJNRGMdf6IN9KbpQn/pUEH2JIoLqQ0Zh 599 | FqYZRmJG1iKmUqKyLB2pqSm6vC1Nm5GXoeatEsVJ0RASR3eNzegikRq5lrV3857Fr/d9ddlICoL+8OfA 600 | Oef/e57zcIT/os7WLMw302muSGJ2689qqi7A44q8IzjtNYzarzHQm8tZtT8FmRqu6LToMxN+B8qhCbGR 601 | KVcDE85ajKUaxoaryEuL4UVXIudPB5Ko2oy98xjDptXERuz3hsgAOTzlqqMk6yjdllzE90UM9Wp5azlB 602 | S1kwkeG+1CSv4mmBQPThfd6Ahqq8GYB4A11yBKmaMLQxoZyLDkGjDiZOFUhUuB+FsWsUQFiArzegtlzH 603 | pFjPpMPA2GA2jucx2KqWK7ZWLqO7dBGP9D5KWLbfto3eAKMhi3FHBeP9GYy9PMXos4OIrYvJrzSRbWjm 604 | wuV6EnVG4tLLiEzSExGf4w0oL05nZEDPaK+akceBuO9v4uPtFUrYo6npbzhdE/QPOQmNSiPouHYOUpaf 605 | gvgqA/dDf9wd63G1r2SgUlAqyyq/1anYUGfG2mdXwne7bOwJUc1AinOS+NxzBpd5HWLbUhyNPvRdF5S2 606 | v05/54tbqvzBifWNHUvPOwLC4/CXwrv2HsB3+w6EwosJOB5ESeElfGpayGD1AmwlArHSm+W2PR1clToo 607 | MrbT0mFTVtlbN6xFuJQar3wQz5Q9VksD+7XyPctrJdx4p5s605M5gKz8lJPSDwtGFbKboJ1blAN52vKb 608 | PdXm80/AfDokTVu+8DfPXv9XCcIPTvjvLQ8YoakAAAAASUVORK5CYII= 609 | 610 | 611 | 612 | 613 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 614 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 615 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 616 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 617 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 618 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 619 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 620 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 621 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 622 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 623 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 624 | 625 | 626 | 627 | 628 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 629 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 630 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 631 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 632 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 633 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 634 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 635 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 636 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 637 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 638 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 639 | 640 | 641 | 642 | 259, 17 643 | 644 | 645 | 17, 17 646 | 647 | 648 | 139, 17 649 | 650 | 651 | 379, 17 652 | 653 | 654 | 655 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 656 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 657 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 658 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 659 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 660 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 661 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 662 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 663 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 664 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 665 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 666 | 667 | 668 | 669 | 670 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 671 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 672 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 673 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 674 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 675 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 676 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 677 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 678 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 679 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 680 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 681 | 682 | 683 | 684 | 500, 17 685 | 686 | 687 | 688 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 689 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 690 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 691 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 692 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 693 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 694 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 695 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 696 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 697 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 698 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 699 | 700 | 701 | 702 | 703 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 704 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 705 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 706 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 707 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 708 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 709 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 710 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 711 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 712 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 713 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 714 | 715 | 716 | 717 | 718 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 719 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIpSURBVDhPtZL/T1JRGMb5p1itrVZbbRpqZbawnBENV1I0 720 | jGlByTSyJTXJwq2oKZQb1KAv6JCYWSxvBrkkZUq4CeQEiRABFeLL072Xa0zRra31bO8v57zP5znnPYf1 721 | X+TxhWF6O7VtGYcnwbSWijKPOLzYrPSvLPwLS3huGUMlT7o9wGD9grVUBj+icdid03S9tDmgNxNwTgVQ 722 | J+rA8XNtWwM+uuZATMwxmQVRycuJFNyzIRitDlScugKzjSgFRGJJaIwEsrk8AsHIhnSL/Ssck37UNipQ 723 | I5DjtuYV7uksRYhr2kebhx2eP6nrycFIEh5fBA/1Nvru8q5+PDaOovK0rABwfwugWzcErfkzHhjsePL6 724 | E7q1VrTdNUDcrgGvSYlDZHN5XTNOnL8BVe8AJAoNDtZfLgDu9L1BPJmikzcrk81hlRwodZJwdBXziwnI 725 | OrVoaOkiT8C8hKLHBPO7CbywOaE1jeC+bhAd6meQdvZC1KoG/5IS3MZ2HObLUHZSggvkWq3wOvbWiAqA 726 | VpWeyStVfCUNf3AZ4zNhfHCFMEDMgye+hYr6FrDLzxQAUuVTpr0ocn74mchg5vsKRt1RcHp2Qv9+kZ78 727 | UcE17KkWFgHNN/uQzgBkGKLJPBZiecyGchjzrmFwPIF++xJUbDbUQzEacIArLpopSRSP4CUN1Obf1Abz 728 | uqob5KjiXwWH/GVl5HPt5zZh37GL2H1EiF1VZ7GDI6CNW5r/TSzWbwHYL0mKJ5czAAAAAElFTkSuQmCC 729 | 730 | 731 | 732 | 841, 17 733 | 734 | -------------------------------------------------------------------------------- /FormDragger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using System.Security; 8 | using System.Text; 9 | using System.Windows.Forms; 10 | 11 | namespace AhDung.WinForm 12 | { 13 | /// 14 | /// 窗体拖拽器 15 | /// - 使窗体客户区可拖动 16 | /// - 若多次调用Application.Run,建议在每次调用之前都启用 17 | /// 18 | [SuppressUnmanagedCodeSecurity] 19 | public static class FormDragger 20 | { 21 | static bool _enabled; 22 | static MouseLeftDownMessageFilter _filter; 23 | 24 | /// 25 | /// 拖拽发生时 26 | /// - 令Cancel = true可取消拖拽 27 | /// - 注意sender为null 28 | /// 29 | public static event EventHandler Dragging; 30 | 31 | private static void OnDragging(FormDraggingCancelEventArgs e) => Dragging?.Invoke(null, e); 32 | 33 | /// 34 | /// 拖拽器开关状态改变后 35 | /// 36 | /// - 注意sender为null 37 | public static event EventHandler EnabledChanged; 38 | 39 | private static void OnEnabledChanged(EventArgs e) => EnabledChanged?.Invoke(null, e); 40 | 41 | /// 42 | /// 获取或设置是否启用拖拽器 43 | /// 44 | public static bool Enabled 45 | { 46 | get => _enabled; 47 | set 48 | { 49 | //先移除再加入。这样做是允许重复Enable, 50 | //因为存在多次Application.Run的情况下,每次Run都有可能会启动新 51 | //线程上下文(ThreadContext),从而导致过滤器因未加入新context 52 | //而失效,所以需要在每次Run之前都启用 53 | 54 | Application.RemoveMessageFilter(_filter); 55 | 56 | if (value) 57 | { 58 | if (_filter == null) 59 | { 60 | _filter = new MouseLeftDownMessageFilter(); 61 | } 62 | Application.AddMessageFilter(_filter); 63 | } 64 | 65 | if (_enabled != value) 66 | { 67 | _enabled = value; 68 | OnEnabledChanged(EventArgs.Empty); 69 | } 70 | } 71 | } 72 | 73 | ///// 74 | ///// 检测本消息过滤器是否还在工作 75 | ///// 76 | ///// 77 | //private static bool FilterExists() 78 | //{ 79 | // if (_filter == null) 80 | // { 81 | // return false; 82 | // } 83 | 84 | // var type = Assembly.GetAssembly(typeof(Application)).GetType("System.Windows.Forms.Application+ThreadContext"); 85 | // var crrThreadContext = type.GetMethod("FromCurrent", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null); 86 | // if (crrThreadContext != null) 87 | // { 88 | // var filterArr = type.GetField("messageFilters", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(crrThreadContext); 89 | // if (filterArr != null) 90 | // { 91 | // return ((ArrayList)filterArr).Contains(_filter); 92 | // } 93 | // } 94 | 95 | // return false; 96 | //} 97 | 98 | static List _excludeControls; 99 | 100 | /// 101 | /// 例外控件 102 | /// 103 | public static List ExcludeControls => _excludeControls ?? (_excludeControls = new List()); 104 | 105 | /// 106 | /// 左键单击消息过滤器 107 | /// 108 | private class MouseLeftDownMessageFilter : IMessageFilter 109 | { 110 | public bool PreFilterMessage(ref Message m) 111 | { 112 | Point point; 113 | switch (m.Msg) 114 | { 115 | case 0x201://WM_LBUTTONDOWN 116 | //System.Diagnostics.Debug.WriteLine(m.HWnd.ToString("X8") + "\t" + m.WParam + "\t" + GetPoint(m.LParam)); 117 | 118 | if ((int)m.WParam != 1) { break; }//仅处理单纯的左键单击 119 | 120 | point = GetPoint(m.LParam); 121 | var c = Control.FromHandle(m.HWnd); 122 | 123 | if (c != null) 124 | { 125 | if (CanDrag(c, point) 126 | || c is UserControl && CanDrag(c.GetChildAtPoint(point), point)) //支持自定义容器控件) 127 | { 128 | return DoDrag(c, point, true); 129 | } 130 | } 131 | else 132 | { 133 | var className = GetClassName(m.HWnd); 134 | 135 | //标头控件。如ListView的标题栏 136 | if (string.Equals("SysHeader32", className, StringComparison.OrdinalIgnoreCase)) 137 | { 138 | var info = new HDHITTESTINFO { pt = (POINT)point }; 139 | var hInfo = GCHandle.Alloc(info, GCHandleType.Pinned); 140 | SendMessage(m.HWnd, 0x1206/*HDM_HITTEST*/, IntPtr.Zero, hInfo.AddrOfPinnedObject()); 141 | info = (HDHITTESTINFO)hInfo.Target; 142 | hInfo.Free(); 143 | 144 | //当点到非列头(右侧)或列头不用来交互(如点击排序)时执行拖动 145 | if (info.flags == 1/*HHT_NOWHERE*/ 146 | || info.flags == 2/*HHT_ONHEADER*/ && !HasStyle(m.HWnd, 2/*HDS_BUTTONS*/)) 147 | { 148 | //标头控件并未封装到.net中,所以FromHandle会得到null,这里取标头控件所在的父控件, 149 | //通常就是ListView,所以其实point是相对于标头控件而不是ListView, 150 | //只不过因为标头控件往往是在LiveView的顶部,所以应该不会引起问题 151 | return DoDrag(Control.FromChildHandle(m.HWnd), point, true); 152 | } 153 | } 154 | } 155 | break; 156 | 157 | case 0xA1://WM_NCLBUTTONDOWN 158 | var ht = (int)m.WParam; 159 | if (ht == 5/*HTMENU*/)//点到MainMenu时 160 | { 161 | //判断是否点到菜单项。若不是或菜单项不可用则拖拽 162 | //点击菜单时m.HWnd为窗体句柄而非菜单句柄 163 | point = GetPoint(m.LParam); 164 | var menu = GetMenu(m.HWnd); 165 | var item = MenuItemFromPoint(m.HWnd, menu, (POINT)point); 166 | if (item == -1 167 | || (GetMenuState(menu, item, 0x400/*MF_BYPOSITION*/) & 2/*MF_DISABLED*/) == 2) 168 | { 169 | return DoDrag(Control.FromHandle(m.HWnd), point, false); 170 | } 171 | } 172 | else if (ht == 4/*HTSIZE*/ || ht == 18/*HTBORDER*/)//点到两个滚动条右下空白、控件边框时 173 | { 174 | return DoDrag(Control.FromHandle(m.HWnd), GetPoint(m.LParam), false); 175 | } 176 | else if (ht == 6/*HTHSCROLL*/ || ht == 7/*HTVSCROLL*/)//点到滚动条时 177 | { 178 | //获取滚动条状态,若处于无效则拖拽 179 | //OBJID_HSCROLL=0xFFFFFFFA 180 | //OBJID_VSCROLL=0xFFFFFFFB 181 | var idObject = unchecked((int)(ht + 0xFFFFFFF4)); 182 | SCROLLBARINFO sbi = new SCROLLBARINFO { cbSize = SizeOfSCROLLBARINFO }; 183 | if (GetScrollBarInfo(m.HWnd, idObject, ref sbi) 184 | && sbi.scrollBarInfo == 1/*STATE_SYSTEM_UNAVAILABLE*/) 185 | { 186 | return DoDrag(Control.FromHandle(m.HWnd), GetPoint(m.LParam), false); 187 | } 188 | } 189 | break; 190 | } 191 | return false; 192 | } 193 | } 194 | 195 | 196 | /// 197 | /// 执行拖拽 198 | /// 199 | /// 指示是否拦截消息 200 | private static bool DoDrag(Control c, Point point, bool isClientArea) 201 | { 202 | try 203 | { 204 | Form form; 205 | if (c == null || (form = c.FindForm()) == null) 206 | { 207 | return false; 208 | } 209 | var e = new FormDraggingCancelEventArgs(c, point, isClientArea); 210 | OnDragging(e); 211 | if (e.Cancel) 212 | { 213 | return false; 214 | } 215 | //当作为MDI子窗体且最大化时,拖MDI主窗体 216 | if (form.WindowState == FormWindowState.Maximized || !form.TopLevel && form.Dock == DockStyle.Fill) 217 | { 218 | form = form.MdiParent ?? form.ParentForm ?? form; 219 | } 220 | SendMessage(form.Handle, 0xA1/*WM_NCLBUTTONDOWN*/, (IntPtr)2, IntPtr.Zero); 221 | return true; 222 | } 223 | catch 224 | { 225 | return false; 226 | } 227 | } 228 | 229 | static PropertyInfo _linkState; 230 | 231 | /// 232 | /// 判断是否处于可拖拽情形 233 | /// 234 | private static bool CanDrag(Control c, Point pt) 235 | { 236 | if (c == null || _excludeControls != null && _excludeControls.Contains(c)) 237 | { 238 | return false; 239 | } 240 | 241 | if (c is Form 242 | || c is Label && !(c is LinkLabel) 243 | || c is Panel 244 | || c is GroupBox 245 | || c is PictureBox 246 | || c is ProgressBar 247 | || c is StatusBar 248 | || c is MdiClient 249 | ) 250 | { 251 | return true; 252 | } 253 | 254 | if (c is LinkLabel linkLabel) 255 | { 256 | //若点到链接部分且链接可用则不拦截 257 | //取State优于调用PointInLink 258 | foreach (LinkLabel.Link link in linkLabel.Links) 259 | { 260 | if (_linkState == null) 261 | { 262 | _linkState = typeof(LinkLabel.Link).GetProperty("State", BindingFlags.Instance | BindingFlags.NonPublic); 263 | } 264 | var state = (LinkState)_linkState.GetValue(link, null); 265 | if ((state & LinkState.Hover) == LinkState.Hover && link.Enabled) 266 | { 267 | return false; 268 | } 269 | } 270 | return true; 271 | } 272 | 273 | if (c is ToolStrip strip) 274 | { 275 | var item = strip.GetItemAt(pt); 276 | if (item == null 277 | || !item.Enabled 278 | || item is ToolStripSeparator 279 | || (item is ToolStripLabel label && !label.IsLink)) 280 | { 281 | return true; 282 | } 283 | return false; 284 | } 285 | 286 | if (c is ToolBar bar) 287 | { 288 | //判断鼠标是否点击在按钮上 289 | var ptPoint = GCHandle.Alloc((POINT)pt, GCHandleType.Pinned); 290 | var index = (int)SendMessage(bar.Handle, (0x400 + 69)/*TB_HITTEST */, IntPtr.Zero, ptPoint.AddrOfPinnedObject()); 291 | ptPoint.Free(); 292 | 293 | //若点击在按钮上且当按钮可用时则不拦截 294 | if (index >= 0 && bar.Buttons[index].Enabled) 295 | { 296 | return false; 297 | } 298 | return true; 299 | } 300 | 301 | if (c is DataGridView dgv) 302 | { 303 | return dgv.HitTest(pt.X, pt.Y).Type == DataGridViewHitTestType.None; 304 | } 305 | 306 | if (c is DataGrid grid) 307 | { 308 | return grid.HitTest(pt).Type == DataGrid.HitTestType.None; 309 | } 310 | 311 | if (c.Parent is UpDownBase) 312 | { 313 | return false; 314 | } 315 | 316 | return !c.CanSelect; // || HasStyle(c.Handle, 0x10000/*WS_EX_CONTROLPARENT*/, true);加上这个有问题,对有Spliter的控件如PropertyGrid不能区分Spliter 317 | } 318 | 319 | #region Win32 API 320 | 321 | // ReSharper disable MemberCanBePrivate.Local 322 | // ReSharper disable FieldCanBeMadeReadOnly.Local 323 | static Point GetPoint(IntPtr lParam) => new Point(unchecked((int)(long)lParam)); 324 | 325 | [DllImport("user32.dll", SetLastError = true)] 326 | static extern bool GetScrollBarInfo(IntPtr hwnd, int idObject, ref SCROLLBARINFO psbi); 327 | 328 | static readonly int SizeOfSCROLLBARINFO = Marshal.SizeOf(typeof(SCROLLBARINFO)); 329 | 330 | [StructLayout(LayoutKind.Sequential)] 331 | private struct SCROLLBARINFO 332 | { 333 | public int cbSize; 334 | public int rcLeft; 335 | public int rcTop; 336 | public int rcRight; 337 | public int rcBottom; 338 | public int dxyLineButton; 339 | public int xyThumbTop; 340 | public int xyThumbBottom; 341 | public int reserved; 342 | public int scrollBarInfo; 343 | public int upArrowInfo; 344 | public int largeDecrementInfo; 345 | public int thumbnfo; 346 | public int largeIncrementInfo; 347 | public int downArrowInfo; 348 | } 349 | 350 | [DllImport("user32.dll")] 351 | static extern int GetMenuState(IntPtr hMenu, int uId, int uFlags); 352 | 353 | [DllImport("user32.dll")] 354 | static extern IntPtr GetMenu(IntPtr hWnd); 355 | 356 | [DllImport("user32.dll")] 357 | static extern int MenuItemFromPoint(IntPtr hWnd, IntPtr hMenu, POINT ptScreen); 358 | 359 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 360 | static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 361 | 362 | [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 363 | static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 364 | 365 | static string GetClassName(IntPtr hWnd) 366 | { 367 | const int MaxClassNameLength = 256; 368 | var sb = new StringBuilder(MaxClassNameLength); 369 | if (GetClassName(hWnd, sb, MaxClassNameLength) == 0) 370 | { 371 | throw new Win32Exception(); 372 | } 373 | return sb.ToString(); 374 | } 375 | 376 | [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowLong")] 377 | static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex); 378 | 379 | [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowLongPtr")] 380 | static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex); 381 | 382 | static int GetWindowStyle(IntPtr hWnd, bool isExStyle = false) 383 | { 384 | var nIndex = isExStyle ? -20/*GWL_EXSTYLE*/: -16/*GWL_STYLE*/; 385 | return unchecked((int)(long)(IntPtr.Size == 4 ? GetWindowLong32(hWnd, nIndex) : GetWindowLongPtr64(hWnd, nIndex))); 386 | } 387 | 388 | static bool HasStyle(IntPtr hWnd, int style, bool isExStyle = false) => 389 | (GetWindowStyle(hWnd, isExStyle) & style) == style; 390 | 391 | [StructLayout(LayoutKind.Sequential)] 392 | private struct POINT 393 | { 394 | public int X; 395 | public int Y; 396 | 397 | public static explicit operator POINT(Point pt) => new POINT { X = pt.X, Y = pt.Y }; 398 | 399 | public static explicit operator Point(POINT pt) => new Point(pt.X, pt.Y); 400 | 401 | public override string ToString() => $"{X}, {Y}"; 402 | } 403 | 404 | [StructLayout(LayoutKind.Sequential)] 405 | private struct HDHITTESTINFO 406 | { 407 | public POINT pt; 408 | public uint flags; 409 | public int iItem; 410 | } 411 | 412 | // ReSharper restore FieldCanBeMadeReadOnly.Local 413 | // ReSharper restore MemberCanBePrivate.Local 414 | 415 | #endregion 416 | } 417 | 418 | /// 419 | /// 420 | /// 窗体拖拽取消事件参数 421 | /// 422 | public class FormDraggingCancelEventArgs : CancelEventArgs 423 | { 424 | /// 425 | /// 获取点击控件 426 | /// 427 | public Control Control { get; } 428 | 429 | /// 430 | /// 获取鼠标位置 431 | /// - 取自点击消息产生时的lParam 432 | /// - 当IsClientArea = true时,相对Control的客户区坐标,否则相对屏幕坐标 433 | /// 434 | public Point MousePosition { get; } 435 | 436 | /// 437 | /// 是否控件客户区 438 | /// 439 | public bool IsClientArea { get; } 440 | 441 | public FormDraggingCancelEventArgs(Control c, Point point, bool isClientArea) 442 | { 443 | Control = c; 444 | MousePosition = point; 445 | IsClientArea = isClientArea; 446 | } 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /FormDraggerDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5} 9 | WinExe 10 | Properties 11 | AhDung 12 | FormDraggerDemo 13 | v2.0 14 | 512 15 | 16 | 17 | x86 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | x86 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | true 37 | bin\Debug\ 38 | DEBUG;TRACE 39 | full 40 | AnyCPU 41 | bin\Debug\FormDraggerDemo.exe.CodeAnalysisLog.xml 42 | true 43 | GlobalSuppressions.cs 44 | prompt 45 | MinimumRecommendedRules.ruleset 46 | ;D:\Microsoft Visual Studio\Team Tools\Static Analysis Tools\\Rule Sets 47 | ;D:\Microsoft Visual Studio\Team Tools\Static Analysis Tools\FxCop\\Rules 48 | 49 | 50 | bin\Release\ 51 | TRACE 52 | true 53 | pdbonly 54 | AnyCPU 55 | bin\Release\FormDraggerDemo.exe.CodeAnalysisLog.xml 56 | true 57 | GlobalSuppressions.cs 58 | prompt 59 | MinimumRecommendedRules.ruleset 60 | ;D:\Microsoft Visual Studio\Team Tools\Static Analysis Tools\\Rule Sets 61 | true 62 | ;D:\Microsoft Visual Studio\Team Tools\Static Analysis Tools\FxCop\\Rules 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | UserControl 76 | 77 | 78 | UserControl 79 | 80 | 81 | 82 | 83 | UserControl 84 | 85 | 86 | 87 | Form 88 | 89 | 90 | FmMDI.cs 91 | 92 | 93 | Form 94 | 95 | 96 | FmTabMDI.cs 97 | 98 | 99 | Form 100 | 101 | 102 | FmTabSub.cs 103 | 104 | 105 | Form 106 | 107 | 108 | FmTestDrag.cs 109 | 110 | 111 | 112 | 113 | 114 | FmMDI.cs 115 | 116 | 117 | FmTabMDI.cs 118 | 119 | 120 | FmTabSub.cs 121 | 122 | 123 | FmTestDrag.cs 124 | 125 | 126 | 127 | 134 | -------------------------------------------------------------------------------- /FormDraggerDemo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FormDraggerDemo", "FormDraggerDemo.csproj", "{70F4498F-A6E3-483B-A75C-BE528DAEF5F5}" 5 | EndProject 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9FCF9ABC-B721-4BCF-BFC4-5342626C2B4C}" 7 | ProjectSection(SolutionItems) = preProject 8 | pic.png = pic.png 9 | README.md = README.md 10 | EndProjectSection 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x86 = Debug|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Debug|x86.ActiveCfg = Debug|x86 23 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Debug|x86.Build.0 = Debug|x86 24 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Release|x86.ActiveCfg = Release|x86 27 | {70F4498F-A6E3-483B-A75C-BE528DAEF5F5}.Release|x86.Build.0 = Release|x86 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using AhDung.WinForm; 4 | 5 | namespace AhDung 6 | { 7 | static class Program 8 | { 9 | /// 10 | /// 应用程序的主入口点。 11 | /// 12 | [STAThread] 13 | static void Main() 14 | { 15 | Application.EnableVisualStyles(); 16 | Application.SetCompatibleTextRenderingDefault(false); 17 | 18 | FormDragger.Enabled = true;//启用拖拽器 19 | //Application.Run(new FmMDI()); 20 | Application.Run(new FmTabMDI()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("FormDraggerDemo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("AhDung")] 12 | [assembly: AssemblyProduct("FormDraggerDemo")] 13 | [assembly: AssemblyCopyright("Copyright © AhDung 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("473aac92-9341-4e61-9dcd-4d7d2d55a66f")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FormDragger 2 | 一个可在窗体内随意拖动窗体的方案。可拖动区域包括不限于Form/Panel/GroupBox/TabControl等空白区域、Label、无效控件、无效菜单/工具栏项、状态栏等等任何你觉得可以拖动的地方。 3 | A solution for easily dragging window within client area nor children control. The range of dragging includes but not limited to blank areas, like Form/Panel/GroupBox/TabControl, also includes anywhere you can drag such as Label, disabled Controls/MenuItems/ToolStripItems, menu/toolbar and status bar. etc. 4 | 5 | ![](pic.png) -------------------------------------------------------------------------------- /pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahdung/FormDraggerDemo/774675932a8f6bfdbb2d2b7ce365d245336a4549/pic.png --------------------------------------------------------------------------------