前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
麻烦博客下方点个【推荐】,谢谢
NuGet
Install-Package HZH_Controls
目录
https://www.cnblogs.com/bfyx/p/11364884.html
用处及效果
目前支持ScrollableControl,TreeView,TextBox的滚动条,只需要在相应的界面上添加组件ScrollbarComponent即可
准备工作
用到了(一)c#Winform自定义控件-基类控件 ,如果你还不了解,可以先去看一下
自定义滚动条有2种方式,1:拦截windows消息,重绘,2:做一个新的,盖上去挡着,这里我们采用的是第二种。
开始
添加一个类UCVScrollbar,继承UCControlBase
一些属性
1 /// <summary> 2 /// The mo large change 3 /// </summary> 4 protected int moLargeChange = 10; 5 /// <summary> 6 /// The mo small change 7 /// </summary> 8 protected int moSmallChange = 1; 9 /// <summary> 10 /// The mo minimum 11 /// </summary> 12 protected int moMinimum = 0; 13 /// <summary> 14 /// The mo maximum 15 /// </summary> 16 protected int moMaximum = 100; 17 /// <summary> 18 /// The mo value 19 /// </summary> 20 protected int moValue = 0; 21 /// <summary> 22 /// The n click point 23 /// </summary> 24 private int nClickPoint; 25 /// <summary> 26 /// The mo thumb top 27 /// </summary> 28 protected int moThumbTop = 0; 29 /// <summary> 30 /// The mo automatic size 31 /// </summary> 32 protected bool moAutoSize = false; 33 /// <summary> 34 /// The mo thumb down 35 /// </summary> 36 private bool moThumbDown = false; 37 /// <summary> 38 /// The mo thumb dragging 39 /// </summary> 40 private bool moThumbDragging = false; 41 /// <summary> 42 /// Occurs when [scroll]. 43 /// </summary> 44 public new event EventHandler Scroll = null; 45 /// <summary> 46 /// Occurs when [value changed]. 47 /// </summary> 48 public event EventHandler ValueChanged = null; 49 50 /// <summary> 51 /// The BTN height 52 /// </summary> 53 private int btnHeight = 18; 54 /// <summary> 55 /// The m int thumb minimum height 56 /// </summary> 57 private int m_intThumbMinHeight = 15; 58 59 /// <summary> 60 /// Gets or sets the height of the BTN. 61 /// </summary> 62 /// <value>The height of the BTN.</value> 63 public int BtnHeight 64 { 65 get { return btnHeight; } 66 set { btnHeight = value; } 67 } 68 /// <summary> 69 /// Gets or sets the large change. 70 /// </summary> 71 /// <value>The large change.</value> 72 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("LargeChange")] 73 public int LargeChange 74 { 75 get { return moLargeChange; } 76 set 77 { 78 moLargeChange = value; 79 Invalidate(); 80 } 81 } 82 83 /// <summary> 84 /// Gets or sets the small change. 85 /// </summary> 86 /// <value>The small change.</value> 87 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("SmallChange")] 88 public int SmallChange 89 { 90 get { return moSmallChange; } 91 set 92 { 93 moSmallChange = value; 94 Invalidate(); 95 } 96 } 97 98 /// <summary> 99 /// Gets or sets the minimum. 100 /// </summary> 101 /// <value>The minimum.</value> 102 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Minimum")] 103 public int Minimum 104 { 105 get { return moMinimum; } 106 set 107 { 108 moMinimum = value; 109 Invalidate(); 110 } 111 } 112 113 /// <summary> 114 /// Gets or sets the maximum. 115 /// </summary> 116 /// <value>The maximum.</value> 117 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Maximum")] 118 public int Maximum 119 { 120 get { return moMaximum; } 121 set 122 { 123 moMaximum = value; 124 Invalidate(); 125 } 126 } 127 128 /// <summary> 129 /// Gets or sets the value. 130 /// </summary> 131 /// <value>The value.</value> 132 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Value")] 133 public int Value 134 { 135 get { return moValue; } 136 set 137 { 138 moValue = value; 139 140 int nTrackHeight = (this.Height - btnHeight * 2); 141 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 142 int nThumbHeight = (int)fThumbHeight; 143 144 if (nThumbHeight > nTrackHeight) 145 { 146 nThumbHeight = nTrackHeight; 147 fThumbHeight = nTrackHeight; 148 } 149 if (nThumbHeight < m_intThumbMinHeight) 150 { 151 nThumbHeight = m_intThumbMinHeight; 152 fThumbHeight = m_intThumbMinHeight; 153 } 154 155 //figure out value 156 int nPixelRange = nTrackHeight - nThumbHeight; 157 int nRealRange = (Maximum - Minimum) - LargeChange; 158 float fPerc = 0.0f; 159 if (nRealRange != 0) 160 { 161 fPerc = (float)moValue / (float)nRealRange; 162 163 } 164 165 float fTop = fPerc * nPixelRange; 166 moThumbTop = (int)fTop; 167 168 169 Invalidate(); 170 } 171 } 172 173 /// <summary> 174 /// Gets or sets a value indicating whether [automatic size]. 175 /// </summary> 176 /// <value><c>true</c> if [automatic size]; otherwise, <c>false</c>.</value> 177 public override bool AutoSize 178 { 179 get 180 { 181 return base.AutoSize; 182 } 183 set 184 { 185 base.AutoSize = value; 186 if (base.AutoSize) 187 { 188 this.Width = 15; 189 } 190 } 191 } 192 193 /// <summary> 194 /// The thumb color 195 /// </summary> 196 private Color thumbColor = Color.FromArgb(255, 77, 58); 197 198 /// <summary> 199 /// Gets or sets the color of the thumb. 200 /// </summary> 201 /// <value>The color of the thumb.</value> 202 public Color ThumbColor 203 { 204 get { return thumbColor; } 205 set { thumbColor = value; } 206 }
重绘
1 protected override void OnPaint(PaintEventArgs e) 2 { 3 base.OnPaint(e); 4 e.Graphics.SetGDIHigh(); 5 6 //draw thumb 7 int nTrackHeight = (this.Height - btnHeight * 2); 8 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 9 int nThumbHeight = (int)fThumbHeight; 10 11 if (nThumbHeight > nTrackHeight) 12 { 13 nThumbHeight = nTrackHeight; 14 fThumbHeight = nTrackHeight; 15 } 16 if (nThumbHeight < m_intThumbMinHeight) 17 { 18 nThumbHeight = m_intThumbMinHeight; 19 fThumbHeight = m_intThumbMinHeight; 20 } 21 int nTop = moThumbTop; 22 nTop += btnHeight; 23 e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(1, nTop, this.Width - 3, nThumbHeight).CreateRoundedRectanglePath(this.ConerRadius)); 24 25 ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, btnHeight - Math.Min(5, this.Width / 2)), Math.Min(5, this.Width / 2), GraphDirection.Upward); 26 ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, this.Height - (btnHeight - Math.Min(5, this.Width / 2))), Math.Min(5, this.Width / 2), GraphDirection.Downward); 27 28 }
处理下鼠标事件
1 /// <summary> 2 /// Handles the MouseDown event of the CustomScrollbar control. 3 /// </summary> 4 /// <param name="sender">The source of the event.</param> 5 /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> 6 private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e) 7 { 8 Point ptPoint = this.PointToClient(Cursor.Position); 9 int nTrackHeight = (this.Height - btnHeight * 2); 10 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 11 int nThumbHeight = (int)fThumbHeight; 12 13 if (nThumbHeight > nTrackHeight) 14 { 15 nThumbHeight = nTrackHeight; 16 fThumbHeight = nTrackHeight; 17 } 18 if (nThumbHeight < m_intThumbMinHeight) 19 { 20 nThumbHeight = m_intThumbMinHeight; 21 fThumbHeight = m_intThumbMinHeight; 22 } 23 24 int nTop = moThumbTop; 25 nTop += btnHeight; 26 27 28 Rectangle thumbrect = new Rectangle(new Point(1, nTop), new Size(this.Width - 2, nThumbHeight)); 29 if (thumbrect.Contains(ptPoint)) 30 { 31 32 //hit the thumb 33 nClickPoint = (ptPoint.Y - nTop); 34 //MessageBox.Show(Convert.ToString((ptPoint.Y - nTop))); 35 this.moThumbDown = true; 36 } 37 38 Rectangle uparrowrect = new Rectangle(new Point(1, 0), new Size(this.Width, btnHeight)); 39 if (uparrowrect.Contains(ptPoint)) 40 { 41 42 int nRealRange = (Maximum - Minimum) - LargeChange; 43 int nPixelRange = (nTrackHeight - nThumbHeight); 44 if (nRealRange > 0) 45 { 46 if (nPixelRange > 0) 47 { 48 if ((moThumbTop - SmallChange) < 0) 49 moThumbTop = 0; 50 else 51 moThumbTop -= SmallChange; 52 53 //figure out value 54 float fPerc = (float)moThumbTop / (float)nPixelRange; 55 float fValue = fPerc * (Maximum - LargeChange); 56 57 moValue = (int)fValue; 58 59 if (ValueChanged != null) 60 ValueChanged(this, new EventArgs()); 61 62 if (Scroll != null) 63 Scroll(this, new EventArgs()); 64 65 Invalidate(); 66 } 67 } 68 } 69 70 Rectangle downarrowrect = new Rectangle(new Point(1, btnHeight + nTrackHeight), new Size(this.Width, btnHeight)); 71 if (downarrowrect.Contains(ptPoint)) 72 { 73 int nRealRange = (Maximum - Minimum) - LargeChange; 74 int nPixelRange = (nTrackHeight - nThumbHeight); 75 if (nRealRange > 0) 76 { 77 if (nPixelRange > 0) 78 { 79 if ((moThumbTop + SmallChange) > nPixelRange) 80 moThumbTop = nPixelRange; 81 else 82 moThumbTop += SmallChange; 83 84 //figure out value 85 float fPerc = (float)moThumbTop / (float)nPixelRange; 86 float fValue = fPerc * (Maximum - LargeChange); 87 88 moValue = (int)fValue; 89 90 if (ValueChanged != null) 91 ValueChanged(this, new EventArgs()); 92 93 if (Scroll != null) 94 Scroll(this, new EventArgs()); 95 96 Invalidate(); 97 } 98 } 99 } 100 } 101 102 /// <summary> 103 /// Handles the MouseUp event of the CustomScrollbar control. 104 /// </summary> 105 /// <param name="sender">The source of the event.</param> 106 /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> 107 private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e) 108 { 109 this.moThumbDown = false; 110 this.moThumbDragging = false; 111 } 112 113 /// <summary> 114 /// Moves the thumb. 115 /// </summary> 116 /// <param name="y">The y.</param> 117 private void MoveThumb(int y) 118 { 119 int nRealRange = Maximum - Minimum; 120 int nTrackHeight = (this.Height - btnHeight * 2); 121 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 122 int nThumbHeight = (int)fThumbHeight; 123 124 if (nThumbHeight > nTrackHeight) 125 { 126 nThumbHeight = nTrackHeight; 127 fThumbHeight = nTrackHeight; 128 } 129 if (nThumbHeight < m_intThumbMinHeight) 130 { 131 nThumbHeight = m_intThumbMinHeight; 132 fThumbHeight = m_intThumbMinHeight; 133 } 134 135 int nSpot = nClickPoint; 136 137 int nPixelRange = (nTrackHeight - nThumbHeight); 138 if (moThumbDown && nRealRange > 0) 139 { 140 if (nPixelRange > 0) 141 { 142 int nNewThumbTop = y - (btnHeight + nSpot); 143 144 if (nNewThumbTop < 0) 145 { 146 moThumbTop = nNewThumbTop = 0; 147 } 148 else if (nNewThumbTop > nPixelRange) 149 { 150 moThumbTop = nNewThumbTop = nPixelRange; 151 } 152 else 153 { 154 moThumbTop = y - (btnHeight + nSpot); 155 } 156 157 158 float fPerc = (float)moThumbTop / (float)nPixelRange; 159 float fValue = fPerc * (Maximum - LargeChange); 160 moValue = (int)fValue; 161 162 Application.DoEvents(); 163 164 Invalidate(); 165 } 166 } 167 } 168 169 /// <summary> 170 /// Handles the MouseMove event of the CustomScrollbar control. 171 /// </summary> 172 /// <param name="sender">The source of the event.</param> 173 /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> 174 private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e) 175 { 176 if (!moThumbDown) 177 return; 178 179 if (moThumbDown == true) 180 { 181 this.moThumbDragging = true; 182 } 183 184 if (this.moThumbDragging) 185 { 186 MoveThumb(e.Y); 187 } 188 189 if (ValueChanged != null) 190 ValueChanged(this, new EventArgs()); 191 192 if (Scroll != null) 193 Scroll(this, new EventArgs()); 194 }
完整代码
1 // *********************************************************************** 2 // Assembly : HZH_Controls 3 // Created : 2019-09-19 4 // 5 // *********************************************************************** 6 // <copyright file="UCVScrollbar.cs"> 7 // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:[email protected] 8 // </copyright> 9 // 10 // Blog: https://www.cnblogs.com/bfyx 11 // GitHub:https://github.com/kwwwvagaa/NetWinformControl 12 // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git 13 // 14 // If you use this code, please keep this note. 15 // *********************************************************************** 16 using System; 17 using System.Collections.Generic; 18 using System.ComponentModel; 19 using System.Drawing; 20 using System.Data; 21 using System.Text; 22 using System.Windows.Forms; 23 using System.Windows.Forms.Design; 24 using System.Diagnostics; 25 26 27 namespace HZH_Controls.Controls 28 { 29 30 /// <summary> 31 /// Class UCVScrollbar. 32 /// Implements the <see cref="HZH_Controls.Controls.UCControlBase" /> 33 /// </summary> 34 /// <seealso cref="HZH_Controls.Controls.UCControlBase" /> 35 [Designer(typeof(ScrollbarControlDesigner))] 36 [DefaultEvent("Scroll")] 37 public class UCVScrollbar : UCControlBase 38 { 39 /// <summary> 40 /// The mo large change 41 /// </summary> 42 protected int moLargeChange = 10; 43 /// <summary> 44 /// The mo small change 45 /// </summary> 46 protected int moSmallChange = 1; 47 /// <summary> 48 /// The mo minimum 49 /// </summary> 50 protected int moMinimum = 0; 51 /// <summary> 52 /// The mo maximum 53 /// </summary> 54 protected int moMaximum = 100; 55 /// <summary> 56 /// The mo value 57 /// </summary> 58 protected int moValue = 0; 59 /// <summary> 60 /// The n click point 61 /// </summary> 62 private int nClickPoint; 63 /// <summary> 64 /// The mo thumb top 65 /// </summary> 66 protected int moThumbTop = 0; 67 /// <summary> 68 /// The mo automatic size 69 /// </summary> 70 protected bool moAutoSize = false; 71 /// <summary> 72 /// The mo thumb down 73 /// </summary> 74 private bool moThumbDown = false; 75 /// <summary> 76 /// The mo thumb dragging 77 /// </summary> 78 private bool moThumbDragging = false; 79 /// <summary> 80 /// Occurs when [scroll]. 81 /// </summary> 82 public new event EventHandler Scroll = null; 83 /// <summary> 84 /// Occurs when [value changed]. 85 /// </summary> 86 public event EventHandler ValueChanged = null; 87 88 /// <summary> 89 /// The BTN height 90 /// </summary> 91 private int btnHeight = 18; 92 /// <summary> 93 /// The m int thumb minimum height 94 /// </summary> 95 private int m_intThumbMinHeight = 15; 96 97 /// <summary> 98 /// Gets or sets the height of the BTN. 99 /// </summary> 100 /// <value>The height of the BTN.</value> 101 public int BtnHeight 102 { 103 get { return btnHeight; } 104 set { btnHeight = value; } 105 } 106 /// <summary> 107 /// Gets or sets the large change. 108 /// </summary> 109 /// <value>The large change.</value> 110 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("LargeChange")] 111 public int LargeChange 112 { 113 get { return moLargeChange; } 114 set 115 { 116 moLargeChange = value; 117 Invalidate(); 118 } 119 } 120 121 /// <summary> 122 /// Gets or sets the small change. 123 /// </summary> 124 /// <value>The small change.</value> 125 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("SmallChange")] 126 public int SmallChange 127 { 128 get { return moSmallChange; } 129 set 130 { 131 moSmallChange = value; 132 Invalidate(); 133 } 134 } 135 136 /// <summary> 137 /// Gets or sets the minimum. 138 /// </summary> 139 /// <value>The minimum.</value> 140 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Minimum")] 141 public int Minimum 142 { 143 get { return moMinimum; } 144 set 145 { 146 moMinimum = value; 147 Invalidate(); 148 } 149 } 150 151 /// <summary> 152 /// Gets or sets the maximum. 153 /// </summary> 154 /// <value>The maximum.</value> 155 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Maximum")] 156 public int Maximum 157 { 158 get { return moMaximum; } 159 set 160 { 161 moMaximum = value; 162 Invalidate(); 163 } 164 } 165 166 /// <summary> 167 /// Gets or sets the value. 168 /// </summary> 169 /// <value>The value.</value> 170 [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Value")] 171 public int Value 172 { 173 get { return moValue; } 174 set 175 { 176 moValue = value; 177 178 int nTrackHeight = (this.Height - btnHeight * 2); 179 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 180 int nThumbHeight = (int)fThumbHeight; 181 182 if (nThumbHeight > nTrackHeight) 183 { 184 nThumbHeight = nTrackHeight; 185 fThumbHeight = nTrackHeight; 186 } 187 if (nThumbHeight < m_intThumbMinHeight) 188 { 189 nThumbHeight = m_intThumbMinHeight; 190 fThumbHeight = m_intThumbMinHeight; 191 } 192 193 //figure out value 194 int nPixelRange = nTrackHeight - nThumbHeight; 195 int nRealRange = (Maximum - Minimum) - LargeChange; 196 float fPerc = 0.0f; 197 if (nRealRange != 0) 198 { 199 fPerc = (float)moValue / (float)nRealRange; 200 201 } 202 203 float fTop = fPerc * nPixelRange; 204 moThumbTop = (int)fTop; 205 206 207 Invalidate(); 208 } 209 } 210 211 /// <summary> 212 /// Gets or sets a value indicating whether [automatic size]. 213 /// </summary> 214 /// <value><c>true</c> if [automatic size]; otherwise, <c>false</c>.</value> 215 public override bool AutoSize 216 { 217 get 218 { 219 return base.AutoSize; 220 } 221 set 222 { 223 base.AutoSize = value; 224 if (base.AutoSize) 225 { 226 this.Width = 15; 227 } 228 } 229 } 230 231 /// <summary> 232 /// The thumb color 233 /// </summary> 234 private Color thumbColor = Color.FromArgb(255, 77, 58); 235 236 /// <summary> 237 /// Gets or sets the color of the thumb. 238 /// </summary> 239 /// <value>The color of the thumb.</value> 240 public Color ThumbColor 241 { 242 get { return thumbColor; } 243 set { thumbColor = value; } 244 } 245 246 /// <summary> 247 /// Initializes a new instance of the <see cref="UCVScrollbar"/> class. 248 /// </summary> 249 public UCVScrollbar() 250 { 251 InitializeComponent(); 252 ConerRadius = 2; 253 FillColor = Color.FromArgb(239, 239, 239); 254 IsShowRect = false; 255 IsRadius = true; 256 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); 257 this.SetStyle(ControlStyles.DoubleBuffer, true); 258 this.SetStyle(ControlStyles.ResizeRedraw, true); 259 this.SetStyle(ControlStyles.Selectable, true); 260 this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); 261 this.SetStyle(ControlStyles.UserPaint, true); 262 } 263 264 265 266 267 /// <summary> 268 /// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 事件。 269 /// </summary> 270 /// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" />。</param> 271 protected override void OnPaint(PaintEventArgs e) 272 { 273 base.OnPaint(e); 274 e.Graphics.SetGDIHigh(); 275 276 //draw thumb 277 int nTrackHeight = (this.Height - btnHeight * 2); 278 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 279 int nThumbHeight = (int)fThumbHeight; 280 281 if (nThumbHeight > nTrackHeight) 282 { 283 nThumbHeight = nTrackHeight; 284 fThumbHeight = nTrackHeight; 285 } 286 if (nThumbHeight < m_intThumbMinHeight) 287 { 288 nThumbHeight = m_intThumbMinHeight; 289 fThumbHeight = m_intThumbMinHeight; 290 } 291 int nTop = moThumbTop; 292 nTop += btnHeight; 293 e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(1, nTop, this.Width - 3, nThumbHeight).CreateRoundedRectanglePath(this.ConerRadius)); 294 295 ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, btnHeight - Math.Min(5, this.Width / 2)), Math.Min(5, this.Width / 2), GraphDirection.Upward); 296 ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, this.Height - (btnHeight - Math.Min(5, this.Width / 2))), Math.Min(5, this.Width / 2), GraphDirection.Downward); 297 298 } 299 300 /// <summary> 301 /// Initializes the component. 302 /// </summary> 303 private void InitializeComponent() 304 { 305 this.SuspendLayout(); 306 // 307 // UCVScrollbar 308 // 309 this.MinimumSize = new System.Drawing.Size(10, 0); 310 this.Name = "UCVScrollbar"; 311 this.Size = new System.Drawing.Size(18, 150); 312 this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseDown); 313 this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseMove); 314 this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseUp); 315 this.ResumeLayout(false); 316 317 } 318 319 /// <summary> 320 /// Handles the MouseDown event of the CustomScrollbar control. 321 /// </summary> 322 /// <param name="sender">The source of the event.</param> 323 /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> 324 private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e) 325 { 326 Point ptPoint = this.PointToClient(Cursor.Position); 327 int nTrackHeight = (this.Height - btnHeight * 2); 328 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 329 int nThumbHeight = (int)fThumbHeight; 330 331 if (nThumbHeight > nTrackHeight) 332 { 333 nThumbHeight = nTrackHeight; 334 fThumbHeight = nTrackHeight; 335 } 336 if (nThumbHeight < m_intThumbMinHeight) 337 { 338 nThumbHeight = m_intThumbMinHeight; 339 fThumbHeight = m_intThumbMinHeight; 340 } 341 342 int nTop = moThumbTop; 343 nTop += btnHeight; 344 345 346 Rectangle thumbrect = new Rectangle(new Point(1, nTop), new Size(this.Width - 2, nThumbHeight)); 347 if (thumbrect.Contains(ptPoint)) 348 { 349 350 //hit the thumb 351 nClickPoint = (ptPoint.Y - nTop); 352 //MessageBox.Show(Convert.ToString((ptPoint.Y - nTop))); 353 this.moThumbDown = true; 354 } 355 356 Rectangle uparrowrect = new Rectangle(new Point(1, 0), new Size(this.Width, btnHeight)); 357 if (uparrowrect.Contains(ptPoint)) 358 { 359 360 int nRealRange = (Maximum - Minimum) - LargeChange; 361 int nPixelRange = (nTrackHeight - nThumbHeight); 362 if (nRealRange > 0) 363 { 364 if (nPixelRange > 0) 365 { 366 if ((moThumbTop - SmallChange) < 0) 367 moThumbTop = 0; 368 else 369 moThumbTop -= SmallChange; 370 371 //figure out value 372 float fPerc = (float)moThumbTop / (float)nPixelRange; 373 float fValue = fPerc * (Maximum - LargeChange); 374 375 moValue = (int)fValue; 376 377 if (ValueChanged != null) 378 ValueChanged(this, new EventArgs()); 379 380 if (Scroll != null) 381 Scroll(this, new EventArgs()); 382 383 Invalidate(); 384 } 385 } 386 } 387 388 Rectangle downarrowrect = new Rectangle(new Point(1, btnHeight + nTrackHeight), new Size(this.Width, btnHeight)); 389 if (downarrowrect.Contains(ptPoint)) 390 { 391 int nRealRange = (Maximum - Minimum) - LargeChange; 392 int nPixelRange = (nTrackHeight - nThumbHeight); 393 if (nRealRange > 0) 394 { 395 if (nPixelRange > 0) 396 { 397 if ((moThumbTop + SmallChange) > nPixelRange) 398 moThumbTop = nPixelRange; 399 else 400 moThumbTop += SmallChange; 401 402 //figure out value 403 float fPerc = (float)moThumbTop / (float)nPixelRange; 404 float fValue = fPerc * (Maximum - LargeChange); 405 406 moValue = (int)fValue; 407 408 if (ValueChanged != null) 409 ValueChanged(this, new EventArgs()); 410 411 if (Scroll != null) 412 Scroll(this, new EventArgs()); 413 414 Invalidate(); 415 } 416 } 417 } 418 } 419 420 /// <summary> 421 /// Handles the MouseUp event of the CustomScrollbar control. 422 /// </summary> 423 /// <param name="sender">The source of the event.</param> 424 /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> 425 private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e) 426 { 427 this.moThumbDown = false; 428 this.moThumbDragging = false; 429 } 430 431 /// <summary> 432 /// Moves the thumb. 433 /// </summary> 434 /// <param name="y">The y.</param> 435 private void MoveThumb(int y) 436 { 437 int nRealRange = Maximum - Minimum; 438 int nTrackHeight = (this.Height - btnHeight * 2); 439 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight; 440 int nThumbHeight = (int)fThumbHeight; 441 442 if (nThumbHeight > nTrackHeight) 443 { 444 nThumbHeight = nTrackHeight; 445 fThumbHeight = nTrackHeight; 446 } 447 if (nThumbHeight < m_intThumbMinHeight) 448 { 449 nThumbHeight = m_intThumbMinHeight; 450 fThumbHeight = m_intThumbMinHeight; 451 } 452 453 int nSpot = nClickPoint; 454 455 int nPixelRange = (nTrackHeight - nThumbHeight); 456 if (moThumbDown && nRealRange > 0) 457 { 458 if (nPixelRange > 0) 459 { 460 int nNewThumbTop = y - (btnHeight + nSpot); 461 462 if (nNewThumbTop < 0) 463 { 464 moThumbTop = nNewThumbTop = 0; 465 } 466 else if (nNewThumbTop > nPixelRange) 467 { 468 moThumbTop = nNewThumbTop = nPixelRange; 469 } 470 else 471 { 472 moThumbTop = y - (btnHeight + nSpot); 473 } 474 475 476 float fPerc = (float)moThumbTop / (float)nPixelRange; 477 float fValue = fPerc * (Maximum - LargeChange); 478 moValue = (int)fValue; 479 480 Application.DoEvents(); 481 482 Invalidate(); 483 } 484 } 485 } 486 487 /// <summary> 488 /// Handles the MouseMove event of the CustomScrollbar control. 489 /// </summary> 490 /// <param name="sender">The source of the event.</param> 491 /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> 492 private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e) 493 { 494 if (!moThumbDown) 495 return; 496 497 if (moThumbDown == true) 498 { 499 this.moThumbDragging = true; 500 } 501 502 if (this.moThumbDragging) 503 { 504 MoveThumb(e.Y); 505 } 506 507 if (ValueChanged != null) 508 ValueChanged(this, new EventArgs()); 509 510 if (Scroll != null) 511 Scroll(this, new EventArgs()); 512 } 513 514 } 515 516 /// <summary> 517 /// Class ScrollbarControlDesigner. 518 /// Implements the <see cref="System.Windows.Forms.Design.ControlDesigner" /> 519 /// </summary> 520 /// <seealso cref="System.Windows.Forms.Design.ControlDesigner" /> 521 internal class ScrollbarControlDesigner : System.Windows.Forms.Design.ControlDesigner 522 { 523 /// <summary> 524 /// 获取指示组件的移动功能的选择规则。 525 /// </summary> 526 /// <value>The selection rules.</value> 527 public override SelectionRules SelectionRules 528 { 529 get 530 { 531 SelectionRules selectionRules = base.SelectionRules; 532 PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(this.Component)["AutoSize"]; 533 if (propDescriptor != null) 534 { 535 bool autoSize = (bool)propDescriptor.GetValue(this.Component); 536 if (autoSize) 537 { 538 selectionRules = SelectionRules.Visible | SelectionRules.Moveable | SelectionRules.BottomSizeable | SelectionRules.TopSizeable; 539 } 540 else 541 { 542 selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable; 543 } 544 } 545 return selectionRules; 546 } 547 } 548 } 549 }
为了方便使用,我们添加一个组件
新增类ScrollbarComponent,继承 Component, IExtenderProvider
实现接口方法
1 public bool CanExtend(object extendee) 2 { 3 if (extendee is ScrollableControl) 4 { 5 ScrollableControl control = (ScrollableControl)extendee; 6 if (control.AutoScroll == true) 7 { 8 return true; 9 } 10 } 11 else if (extendee is TreeView) 12 { 13 TreeView control = (TreeView)extendee; 14 if (control.Scrollable) 15 { 16 return true; 17 } 18 } 19 else if (extendee is TextBox) 20 { 21 TextBox control = (TextBox)extendee; 22 if (control.Multiline && control.ScrollBars != ScrollBars.None) 23 { 24 return true; 25 } 26 } 27 return false; 28 }
扩展控件属性
1 [Browsable(true), Category("自定义属性"), Description("是否使用自定义滚动条"), DisplayName("UserCustomScrollbar"), Localizable(true)] 2 public bool GetUserCustomScrollbar(Control control) 3 { 4 return m_blnUserCustomScrollbar; 5 } 6 7 public void SetUserCustomScrollbar(Control control, bool blnUserCustomScrollbar) 8 { 9 m_blnUserCustomScrollbar = blnUserCustomScrollbar; 10 control.VisibleChanged += control_VisibleChanged; 11 control.SizeChanged += control_SizeChanged; 12 control.LocationChanged += control_LocationChanged; 13 control.Disposed += control_Disposed; 14 15 if (control is TreeView) 16 { 17 TreeView tv = (TreeView)control; 18 tv.MouseWheel += tv_MouseWheel; 19 tv.AfterSelect += tv_AfterSelect; 20 tv.AfterExpand += tv_AfterExpand; 21 tv.AfterCollapse += tv_AfterCollapse; 22 } 23 else if (control is TextBox) 24 { 25 TextBox txt = (TextBox)control; 26 txt.MouseWheel += txt_MouseWheel; 27 txt.TextChanged += txt_TextChanged; 28 29 txt.KeyDown += txt_KeyDown; 30 } 31 control_SizeChanged(control, null); 32 } 33
处理一下控件什么时候添加滚动条,什么时候移除滚动条,以及滚动条位置大小的改变等
1 void control_Disposed(object sender, EventArgs e) 2 { 3 Control control = (Control)sender; 4 if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) 5 { 6 m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]); 7 m_lstVCache.Remove(control); 8 } 9 } 10 11 void control_LocationChanged(object sender, EventArgs e) 12 { 13 ResetVScrollLocation(sender); 14 } 15 16 void control_SizeChanged(object sender, EventArgs e) 17 { 18 if (ControlHelper.IsDesignMode()) 19 { 20 return; 21 } 22 else 23 { 24 var control = sender as Control; 25 26 bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0; 27 bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0; 28 if (blnHasVScrollbar) 29 { 30 if (!m_lstVCache.ContainsKey(control)) 31 { 32 if (control.Parent != null) 33 { 34 UCVScrollbar barV = new UCVScrollbar(); 35 barV.Scroll += barV_Scroll; 36 m_lstVCache[control] = barV; 37 if (blnHasHScrollbar) 38 { 39 barV.Height = control.Height - barV.Width - 2; 40 } 41 else 42 { 43 barV.Height = control.Height - 2; 44 } 45 SetVMaxNum(control); 46 barV.Location = new System.Drawing.Point(control.Right - barV.Width - 1, control.Top + 1); 47 control.Parent.Controls.Add(barV); 48 int intControlIndex = control.Parent.Controls.GetChildIndex(control); 49 control.Parent.Controls.SetChildIndex(barV, intControlIndex); 50 } 51 } 52 else 53 { 54 SetVMaxNum(control); 55 } 56 } 57 else 58 { 59 if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) 60 { 61 m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]); 62 m_lstVCache.Remove(control); 63 } 64 } 65 66 //if (blnHasHScrollbar) 67 //{ 68 // if (control.Parent != null) 69 // { 70 71 // } 72 //} 73 //else 74 //{ 75 // if (m_lstHCache.ContainsKey(control)) 76 // { 77 // if (m_lstHCache[control].Visible) 78 // { 79 // m_lstHCache[control].Parent.Controls.Remove(m_lstHCache[control]); 80 // } 81 // } 82 //} 83 } 84 ResetVScrollLocation(sender); 85 } 86 87 private void SetVMaxNum(Control control) 88 { 89 if (!m_lstVCache.ContainsKey(control)) 90 return; 91 UCVScrollbar barV = m_lstVCache[control]; 92 if (control is ScrollableControl) 93 { 94 barV.Maximum = (control as ScrollableControl).VerticalScroll.Maximum; 95 barV.Value = (control as ScrollableControl).VerticalScroll.Value; 96 } 97 else if (control is TreeView) 98 { 99 barV.Maximum = GetTreeNodeMaxY(control as TreeView); 100 barV.Value = (control as TreeView).AutoScrollOffset.Y; 101 } 102 else if (control is TextBox) 103 { 104 TextBox txt = (TextBox)control; 105 int intTxtMaxHeight = 0; 106 int intTextHeight = 0; 107 using (var g = txt.CreateGraphics()) 108 { 109 intTxtMaxHeight = (int)g.MeasureString(txt.Text, txt.Font).Height; 110 intTextHeight = (int)g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font).Height; 111 } 112 barV.Maximum = intTxtMaxHeight; 113 barV.Value = (control as TextBox).AutoScrollOffset.Y; 114 } 115 } 116 /// <summary> 117 /// Resets the v scroll location. 118 /// </summary> 119 /// <param name="sender">The sender.</param> 120 private void ResetVScrollLocation(object sender) 121 { 122 Control control = (Control)sender; 123 bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0; 124 bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0; 125 if (control.Visible) 126 { 127 if (m_lstVCache.ContainsKey(control)) 128 { 129 m_lstVCache[control].Location = new System.Drawing.Point(control.Right - m_lstVCache[control].Width - 1, control.Top + 1); 130 if (blnHasHScrollbar) 131 { 132 m_lstVCache[control].Height = control.Height - m_lstVCache[control].Width - 2; 133 } 134 else 135 { 136 m_lstVCache[control].Height = control.Height - 2; 137 } 138 } 139 } 140 } 141 /// <summary> 142 /// Handles the VisibleChanged event of the control control. 143 /// </summary> 144 /// <param name="sender">The source of the event.</param> 145 /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> 146 void control_VisibleChanged(object sender, EventArgs e) 147 { 148 Control control = (Control)sender; 149 if (!control.Visible) 150 { 151 if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) 152 { 153 m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]); 154 m_lstVCache.Remove(control); 155 } 156 } 157 } 158 159 private const int HSCROLL = 0x100000; 160 private const int VSCROLL = 0x200000; 161 private const int STYLE = -16; 162 163 private Dictionary<Control, UCVScrollbar> m_lstVCache = new Dictionary<Control, UCVScrollbar>(); 164 //private Dictionary<ScrollableControl, UCVScrollbar> m_lstHCache = new Dictionary<ScrollableControl, UCVScrollbar>(); 165 166 void barV_Scroll(object sender, EventArgs e) 167 { 168 UCVScrollbar bar = (UCVScrollbar)sender; 169 if (m_lstVCache.ContainsValue(bar)) 170 { 171 Control c = m_lstVCache.FirstOrDefault(p => p.Value == bar).Key; 172 if (c is ScrollableControl) 173 { 174 (c as ScrollableControl).AutoScrollPosition = new Point(0, bar.Value); 175 } 176 else if (c is TreeView) 177 { 178 TreeView tv = (c as TreeView); 179 SetTreeViewScrollLocation(tv, tv.Nodes, bar.Value); 180 } 181 else if (c is TextBox) 182 { 183 TextBox txt = (c as TextBox); 184 SetTextBoxScrollLocation(txt, bar.Value); 185 } 186 } 187 } 188 189 #region Treeview处理 English:Treeview\u5904\u7406 190 void tv_AfterCollapse(object sender, TreeViewEventArgs e) 191 { 192 control_SizeChanged(sender as Control, null); 193 } 194 195 void tv_AfterExpand(object sender, TreeViewEventArgs e) 196 { 197 control_SizeChanged(sender as Control, null); 198 } 199 /// <summary> 200 /// Gets the tree node 最大高度 201 /// </summary> 202 /// <param name="tv">The tv.</param> 203 /// <returns>System.Int32.</returns> 204 private int GetTreeNodeMaxY(TreeView tv) 205 { 206 TreeNode tnLast = tv.Nodes[tv.Nodes.Count - 1]; 207 begin: 208 if (tnLast.IsExpanded && tnLast.Nodes.Count > 0) 209 { 210 tnLast = tnLast.LastNode; 211 goto begin; 212 } 213 return tnLast.Bounds.Bottom; 214 } 215 void tv_AfterSelect(object sender, TreeViewEventArgs e) 216 { 217 TreeView tv = (TreeView)sender; 218 if (m_lstVCache.ContainsKey(tv)) 219 { 220 m_lstVCache[tv].Value = tv.Nodes.Count > 0 ? Math.Abs(tv.Nodes[0].Bounds.Top) : 0; 221 } 222 } 223 224 void tv_MouseWheel(object sender, MouseEventArgs e) 225 { 226 TreeView tv = (TreeView)sender; 227 if (m_lstVCache.ContainsKey(tv)) 228 { 229 m_lstVCache[tv].Value = tv.Nodes.Count > 0 ? Math.Abs(tv.Nodes[0].Bounds.Top) : 0; 230 } 231 } 232 /// <summary> 233 /// Sets the TreeView scroll location. 234 /// </summary> 235 /// <param name="tv">The tv.</param> 236 /// <param name="tns">The TNS.</param> 237 /// <param name="intY">The int y.</param> 238 /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> 239 private bool SetTreeViewScrollLocation(TreeView tv, TreeNodeCollection tns, int intY) 240 { 241 for (int i = 0; i < tns.Count; i++) 242 { 243 if (intY >= tns[i].Bounds.Top - tv.Nodes[0].Bounds.Top - 3 && intY <= tns[i].Bounds.Bottom - tv.Nodes[0].Bounds.Top + 3) 244 { 245 tns[i].EnsureVisible(); 246 return true; 247 } 248 else if (tns[i].IsExpanded && tns[i].Nodes.Count > 0) 249 { 250 bool bln = SetTreeViewScrollLocation(tv, tns[i].Nodes, intY); 251 if (bln) 252 return true; 253 } 254 } 255 return false; 256 } 257 #endregion 258 259 #region TextBox处理 English:TextBox Processing 260 261 void txt_TextChanged(object sender, EventArgs e) 262 { 263 TextBox txt = sender as TextBox; 264 control_SizeChanged(txt, null); 265 SetVMaxNum(txt); 266 if (m_lstVCache.ContainsKey(txt)) 267 { 268 using (var g = txt.CreateGraphics()) 269 { 270 var size = g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font); 271 m_lstVCache[txt].Value = (int)size.Height; 272 } 273 } 274 } 275 private void SetTextBoxScrollLocation(TextBox txt, int intY) 276 { 277 using (var g = txt.CreateGraphics()) 278 { 279 for (int i = 0; i < txt.Lines.Length; i++) 280 { 281 string str = string.Join("\n", txt.Lines.Take(i + 1)); 282 var size = g.MeasureString(str, txt.Font); 283 if (size.Height >= intY) 284 { 285 txt.SelectionStart = str.Length; 286 txt.ScrollToCaret(); 287 return; 288 } 289 } 290 } 291 } 292 293 void txt_KeyDown(object sender, KeyEventArgs e) 294 { 295 if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) 296 { 297 TextBox txt = (TextBox)sender; 298 if (m_lstVCache.ContainsKey(txt)) 299 { 300 using (var g = txt.CreateGraphics()) 301 { 302 var size = g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font); 303 m_lstVCache[txt].Value = (int)size.Height; 304 } 305 } 306 } 307 } 308 309 void txt_MouseWheel(object sender, MouseEventArgs e) 310 { 311 TextBox txt = (TextBox)sender; 312 if (m_lstVCache.ContainsKey(txt)) 313 { 314 using (var g = txt.CreateGraphics()) 315 { 316 StringBuilder str = new StringBuilder(); 317 for (int i = 0; i < System.Windows.Forms.SystemInformation.MouseWheelScrollLines; i++) 318 { 319 str.AppendLine("A"); 320 } 321 var height = (int)g.MeasureString(str.ToString(), txt.Font).Height; 322 if (e.Delta < 0) 323 { 324 if (height + m_lstVCache[txt].Value > m_lstVCache[txt].Maximum) 325 m_lstVCache[txt].Value = m_lstVCache[txt].Maximum; 326 else 327 m_lstVCache[txt].Value += height; 328 } 329 else 330 { 331 if (m_lstVCache[txt].Value - height < 0) 332 m_lstVCache[txt].Value = 0; 333 else 334 m_lstVCache[txt].Value -= height; 335 } 336 } 337 } 338 } 339 #endregion
完整代码
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Linq; 6 using System.Text; 7 using System.Windows.Forms; 8 9 namespace HZH_Controls.Controls.ScrollBar 10 { 11 [ProvideProperty("UserCustomScrollbar", typeof(Control))] 12 public class ScrollbarComponent : Component, IExtenderProvider 13 { 14 public ScrollbarComponent() 15 { 16 } 17 18 public ScrollbarComponent(IContainer container) 19 { 20 container.Add(this); 21 } 22 bool m_blnUserCustomScrollbar = true; 23 public bool CanExtend(object extendee) 24 { 25 if (extendee is ScrollableControl) 26 { 27 ScrollableControl control = (ScrollableControl)extendee; 28 if (control.AutoScroll == true) 29 { 30 return true; 31 } 32 } 33 else if (extendee is TreeView) 34 { 35 TreeView control = (TreeView)extendee; 36 if (control.Scrollable) 37 { 38 return true; 39 } 40 } 41 else if (extendee is TextBox) 42 { 43 TextBox control = (TextBox)extendee; 44 if (control.Multiline && control.ScrollBars != ScrollBars.None) 45 { 46 return true; 47 } 48 } 49 return false; 50 } 51 52 [Browsable(true), Category("自定义属性"), Description("是否使用自定义滚动条"), DisplayName("UserCustomScrollbar"), Localizable(true)] 53 public bool GetUserCustomScrollbar(Control control) 54 { 55 return m_blnUserCustomScrollbar; 56 } 57 58 public void SetUserCustomScrollbar(Control control, bool blnUserCustomScrollbar) 59 { 60 m_blnUserCustomScrollbar = blnUserCustomScrollbar; 61 control.VisibleChanged += control_VisibleChanged; 62 control.SizeChanged += control_SizeChanged; 63 control.LocationChanged += control_LocationChanged; 64 control.Disposed += control_Disposed; 65 66 if (control is TreeView) 67 { 68 TreeView tv = (TreeView)control; 69 tv.MouseWheel += tv_MouseWheel; 70 tv.AfterSelect += tv_AfterSelect; 71 tv.AfterExpand += tv_AfterExpand; 72 tv.AfterCollapse += tv_AfterCollapse; 73 } 74 else if (control is TextBox) 75 { 76 TextBox txt = (TextBox)control; 77 txt.MouseWheel += txt_MouseWheel; 78 txt.TextChanged += txt_TextChanged; 79 80 txt.KeyDown += txt_KeyDown; 81 } 82 control_SizeChanged(control, null); 83 } 84 85 86 void control_Disposed(object sender, EventArgs e) 87 { 88 Control control = (Control)sender; 89 if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) 90 { 91 m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]); 92 m_lstVCache.Remove(control); 93 } 94 } 95 96 void control_LocationChanged(object sender, EventArgs e) 97 { 98 ResetVScrollLocation(sender); 99 } 100 101 void control_SizeChanged(object sender, EventArgs e) 102 { 103 if (ControlHelper.IsDesignMode()) 104 { 105 return; 106 } 107 else 108 { 109 var control = sender as Control; 110 111 bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0; 112 bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0; 113 if (blnHasVScrollbar) 114 { 115 if (!m_lstVCache.ContainsKey(control)) 116 { 117 if (control.Parent != null) 118 { 119 UCVScrollbar barV = new UCVScrollbar(); 120 barV.Scroll += barV_Scroll; 121 m_lstVCache[control] = barV; 122 if (blnHasHScrollbar) 123 { 124 barV.Height = control.Height - barV.Width - 2; 125 } 126 else 127 { 128 barV.Height = control.Height - 2; 129 } 130 SetVMaxNum(control); 131 barV.Location = new System.Drawing.Point(control.Right - barV.Width - 1, control.Top + 1); 132 control.Parent.Controls.Add(barV); 133 int intControlIndex = control.Parent.Controls.GetChildIndex(control); 134 control.Parent.Controls.SetChildIndex(barV, intControlIndex); 135 } 136 } 137 else 138 { 139 SetVMaxNum(control); 140 } 141 } 142 else 143 { 144 if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) 145 { 146 m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]); 147 m_lstVCache.Remove(control); 148 } 149 } 150 151 //if (blnHasHScrollbar) 152 //{ 153 // if (control.Parent != null) 154 // { 155 156 // } 157 //} 158 //else 159 //{ 160 // if (m_lstHCache.ContainsKey(control)) 161 // { 162 // if (m_lstHCache[control].Visible) 163 // { 164 // m_lstHCache[control].Parent.Controls.Remove(m_lstHCache[control]); 165 // } 166 // } 167 //} 168 } 169 ResetVScrollLocation(sender); 170 } 171 172 private void SetVMaxNum(Control control) 173 { 174 if (!m_lstVCache.ContainsKey(control)) 175 return; 176 UCVScrollbar barV = m_lstVCache[control]; 177 if (control is ScrollableControl) 178 { 179 barV.Maximum = (control as ScrollableControl).VerticalScroll.Maximum; 180 barV.Value = (control as ScrollableControl).VerticalScroll.Value; 181 } 182 else if (control is TreeView) 183 { 184 barV.Maximum = GetTreeNodeMaxY(control as TreeView); 185 barV.Value = (control as TreeView).AutoScrollOffset.Y; 186 } 187 else if (control is TextBox) 188 { 189 TextBox txt = (TextBox)control; 190 int intTxtMaxHeight = 0; 191 int intTextHeight = 0; 192 using (var g = txt.CreateGraphics()) 193 { 194 intTxtMaxHeight = (int)g.MeasureString(txt.Text, txt.Font).Height; 195 intTextHeight = (int)g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font).Height; 196 } 197 barV.Maximum = intTxtMaxHeight; 198 barV.Value = (control as TextBox).AutoScrollOffset.Y; 199 } 200 } 201 /// <summary> 202 /// Resets the v scroll location. 203 /// </summary> 204 /// <param name="sender">The sender.</param> 205 private void ResetVScrollLocation(object sender) 206 { 207 Control control = (Control)sender; 208 bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0; 209 bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0; 210 if (control.Visible) 211 { 212 if (m_lstVCache.ContainsKey(control)) 213 { 214 m_lstVCache[control].Location = new System.Drawing.Point(control.Right - m_lstVCache[control].Width - 1, control.Top + 1); 215 if (blnHasHScrollbar) 216 { 217 m_lstVCache[control].Height = control.Height - m_lstVCache[control].Width - 2; 218 } 219 else 220 { 221 m_lstVCache[control].Height = control.Height - 2; 222 } 223 } 224 } 225 } 226 /// <summary> 227 /// Handles the VisibleChanged event of the control control. 228 /// </summary> 229 /// <param name="sender">The source of the event.</param> 230 /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> 231 void control_VisibleChanged(object sender, EventArgs e) 232 { 233 Control control = (Control)sender; 234 if (!control.Visible) 235 { 236 if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null) 237 { 238 m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]); 239 m_lstVCache.Remove(control); 240 } 241 } 242 } 243 244 private const int HSCROLL = 0x100000; 245 private const int VSCROLL = 0x200000; 246 private const int STYLE = -16; 247 248 private Dictionary<Control, UCVScrollbar> m_lstVCache = new Dictionary<Control, UCVScrollbar>(); 249 //private Dictionary<ScrollableControl, UCVScrollbar> m_lstHCache = new Dictionary<ScrollableControl, UCVScrollbar>(); 250 251 void barV_Scroll(object sender, EventArgs e) 252 { 253 UCVScrollbar bar = (UCVScrollbar)sender; 254 if (m_lstVCache.ContainsValue(bar)) 255 { 256 Control c = m_lstVCache.FirstOrDefault(p => p.Value == bar).Key; 257 if (c is ScrollableControl) 258 { 259 (c as ScrollableControl).AutoScrollPosition = new Point(0, bar.Value); 260 } 261 else if (c is TreeView) 262 { 263 TreeView tv = (c as TreeView); 264 SetTreeViewScrollLocation(tv, tv.Nodes, bar.Value); 265 } 266 else if (c is TextBox) 267 { 268 TextBox txt = (c as TextBox); 269 SetTextBoxScrollLocation(txt, bar.Value); 270 } 271 } 272 } 273 274 #region Treeview处理 English:Treeview\u5904\u7406 275 void tv_AfterCollapse(object sender, TreeViewEventArgs e) 276 { 277 control_SizeChanged(sender as Control, null); 278 } 279 280 void tv_AfterExpand(object sender, TreeViewEventArgs e) 281 { 282 control_SizeChanged(sender as Control, null); 283 } 284 /// <summary> 285 /// Gets the tree node 最大高度 286 /// </summary> 287 /// <param name="tv">The tv.</param> 288 /// <returns>System.Int32.</returns> 289 private int GetTreeNodeMaxY(TreeView tv) 290 { 291 TreeNode tnLast = tv.Nodes[tv.Nodes.Count - 1]; 292 begin: 293 if (tnLast.IsExpanded && tnLast.Nodes.Count > 0) 294 { 295 tnLast = tnLast.LastNode; 296 goto begin; 297 } 298 return tnLast.Bounds.Bottom; 299 } 300 void tv_AfterSelect(object sender, TreeViewEventArgs e) 301 { 302 TreeView tv = (TreeView)sender; 303 if (m_lstVCache.ContainsKey(tv)) 304 { 305 m_lstVCache[tv].Value = tv.Nodes.Count > 0 ? Math.Abs(tv.Nodes[0].Bounds.Top) : 0; 306 } 307 } 308 309 void tv_MouseWheel(object sender, MouseEventArgs e) 310 { 311 TreeView tv = (TreeView)sender; 312 if (m_lstVCache.ContainsKey(tv)) 313 { 314 m_lstVCache[tv].Value = tv.Nodes.Count > 0 ? Math.Abs(tv.Nodes[0].Bounds.Top) : 0; 315 } 316 } 317 /// <summary> 318 /// Sets the TreeView scroll location. 319 /// </summary> 320 /// <param name="tv">The tv.</param> 321 /// <param name="tns">The TNS.</param> 322 /// <param name="intY">The int y.</param> 323 /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> 324 private bool SetTreeViewScrollLocation(TreeView tv, TreeNodeCollection tns, int intY) 325 { 326 for (int i = 0; i < tns.Count; i++) 327 { 328 if (intY >= tns[i].Bounds.Top - tv.Nodes[0].Bounds.Top - 3 && intY <= tns[i].Bounds.Bottom - tv.Nodes[0].Bounds.Top + 3) 329 { 330 tns[i].EnsureVisible(); 331 return true; 332 } 333 else if (tns[i].IsExpanded && tns[i].Nodes.Count > 0) 334 { 335 bool bln = SetTreeViewScrollLocation(tv, tns[i].Nodes, intY); 336 if (bln) 337 return true; 338 } 339 } 340 return false; 341 } 342 #endregion 343 344 #region TextBox处理 English:TextBox Processing 345 346 void txt_TextChanged(object sender, EventArgs e) 347 { 348 TextBox txt = sender as TextBox; 349 control_SizeChanged(txt, null); 350 SetVMaxNum(txt); 351 if (m_lstVCache.ContainsKey(txt)) 352 { 353 using (var g = txt.CreateGraphics()) 354 { 355 var size = g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font); 356 m_lstVCache[txt].Value = (int)size.Height; 357 } 358 } 359 } 360 private void SetTextBoxScrollLocation(TextBox txt, int intY) 361 { 362 using (var g = txt.CreateGraphics()) 363 { 364 for (int i = 0; i < txt.Lines.Length; i++) 365 { 366 string str = string.Join("\n", txt.Lines.Take(i + 1)); 367 var size = g.MeasureString(str, txt.Font); 368 if (size.Height >= intY) 369 { 370 txt.SelectionStart = str.Length; 371 txt.ScrollToCaret(); 372 return; 373 } 374 } 375 } 376 } 377 378 void txt_KeyDown(object sender, KeyEventArgs e) 379 { 380 if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down) 381 { 382 TextBox txt = (TextBox)sender; 383 if (m_lstVCache.ContainsKey(txt)) 384 { 385 using (var g = txt.CreateGraphics()) 386 { 387 var size = g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font); 388 m_lstVCache[txt].Value = (int)size.Height; 389 } 390 } 391 } 392 } 393 394 void txt_MouseWheel(object sender, MouseEventArgs e) 395 { 396 TextBox txt = (TextBox)sender; 397 if (m_lstVCache.ContainsKey(txt)) 398 { 399 using (var g = txt.CreateGraphics()) 400 { 401 StringBuilder str = new StringBuilder(); 402 for (int i = 0; i < System.Windows.Forms.SystemInformation.MouseWheelScrollLines; i++) 403 { 404 str.AppendLine("A"); 405 } 406 var height = (int)g.MeasureString(str.ToString(), txt.Font).Height; 407 if (e.Delta < 0) 408 { 409 if (height + m_lstVCache[txt].Value > m_lstVCache[txt].Maximum) 410 m_lstVCache[txt].Value = m_lstVCache[txt].Maximum; 411 else 412 m_lstVCache[txt].Value += height; 413 } 414 else 415 { 416 if (m_lstVCache[txt].Value - height < 0) 417 m_lstVCache[txt].Value = 0; 418 else 419 m_lstVCache[txt].Value -= height; 420 } 421 } 422 } 423 } 424 #endregion 425 } 426 }
代码就这些了
使用的时候,只需要在界面上添加组件ScrollbarComponent即可
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧