官網
http://www.hzhcontrols.com
前提
入行已經7,8年了,一直想做一套漂亮點的自定義控制元件,于是就有了本系列文章,
GitHub:https://github.com/kwwwvagaa/NetWinformControl
碼云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果覺得寫的還行,請點個 star 支持一下吧
歡迎前來交流探討: 企鵝群568015492 
麻煩博客下方點個【推薦】,謝謝
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 = https://www.cnblogs.com/bfyx/p/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 Minimum104 {105 get { return moMinimum; }106 set107 {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 Maximum119 {120 get { return moMaximum; }121 set122 {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 Value134 {135 get { return moValue; }136 set137 {138 moValue =https://www.cnblogs.com/bfyx/p/ 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 value156 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 AutoSize178 {179 get180 {181 return base.AutoSize;182 }183 set184 {185 base.AutoSize = value;186 if (base.AutoSize)187 {188 this.Width = 15;189 }190 }191 }192 193 /// <summary>194 /// The thumb color195 /// </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 ThumbColor203 {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 = https://www.cnblogs.com/bfyx/p/fPerc * (Maximum - LargeChange); 56 57 moValue = https://www.cnblogs.com/bfyx/p/(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 = https://www.cnblogs.com/bfyx/p/fPerc * (Maximum - LargeChange); 87 88 moValue = https://www.cnblogs.com/bfyx/p/(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 else153 {154 moThumbTop = y - (btnHeight + nSpot);155 }156 157 158 float fPerc = (float)moThumbTop / (float)nPixelRange;159 float fValue = https://www.cnblogs.com/bfyx/p/fPerc * (Maximum - LargeChange);160 moValue = https://www.cnblogs.com/bfyx/p/(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 = https://www.cnblogs.com/bfyx/p/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 BtnHeight102 {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 LargeChange112 {113 get { return moLargeChange; }114 set115 {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 SmallChange127 {128 get { return moSmallChange; }129 set130 {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 Minimum142 {143 get { return moMinimum; }144 set145 {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 Maximum157 {158 get { return moMaximum; }159 set160 {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 Value172 {173 get { return moValue; }174 set175 {176 moValue =https://www.cnblogs.com/bfyx/p/ 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 value194 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 AutoSize216 {217 get218 {219 return base.AutoSize;220 }221 set222 {223 base.AutoSize = value;224 if (base.AutoSize)225 {226 this.Width = 15;227 }228 }229 }230 231 /// <summary>232 /// The thumb color233 /// </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 ThumbColor241 {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 thumb277 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 // UCVScrollbar308 // 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 thumb351 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 else369 moThumbTop -= SmallChange;370 371 //figure out value372 float fPerc = (float)moThumbTop / (float)nPixelRange;373 float fValue = https://www.cnblogs.com/bfyx/p/fPerc * (Maximum - LargeChange);374 375 moValue = https://www.cnblogs.com/bfyx/p/(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 else400 moThumbTop += SmallChange;401 402 //figure out value403 float fPerc = (float)moThumbTop / (float)nPixelRange;404 float fValue = https://www.cnblogs.com/bfyx/p/fPerc * (Maximum - LargeChange);405 406 moValue = https://www.cnblogs.com/bfyx/p/(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 else471 {472 moThumbTop = y - (btnHeight + nSpot);473 }474 475 476 float fPerc = (float)moThumbTop / (float)nPixelRange;477 float fValue = https://www.cnblogs.com/bfyx/p/fPerc * (Maximum - LargeChange);478 moValue = https://www.cnblogs.com/bfyx/p/(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.ControlDesigner522 {523 /// <summary>524 /// 獲取指示組件的移動功能的選擇規則,525 /// </summary>526 /// <value>The selection rules.</value>527 public override SelectionRules SelectionRules528 {529 get530 {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 else541 {542 selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable;543 }544 }545 return selectionRules;546 }547 }548 }549 }View Code
為了方便使用,我們添加一個組件
新增類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 = https://www.cnblogs.com/bfyx/p/(control as ScrollableControl).VerticalScroll.Value; 96 } 97 else if (control is TreeView) 98 { 99 barV.Maximum = GetTreeNodeMaxY(control as TreeView);100 barV.Value = https://www.cnblogs.com/bfyx/p/(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 = https://www.cnblogs.com/bfyx/p/(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 else135 {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 =https://www.cnblogs.com/bfyx/p/= 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\u7406190 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 = https://www.cnblogs.com/bfyx/p/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 = https://www.cnblogs.com/bfyx/p/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 #endregion258 259 #region TextBox處理 English:TextBox Processing260 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 = https://www.cnblogs.com/bfyx/p/(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 = https://www.cnblogs.com/bfyx/p/(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 =https://www.cnblogs.com/bfyx/p/ m_lstVCache[txt].Maximum;326 else327 m_lstVCache[txt].Value += height;328 }329 else330 {331 if (m_lstVCache[txt].Value - height < 0)332 m_lstVCache[txt].Value = https://www.cnblogs.com/bfyx/p/0;333 else334 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 else108 {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 else127 {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 else138 {139 SetVMaxNum(control);140 }141 }142 else143 {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 //else159 //{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 = https://www.cnblogs.com/bfyx/p/(control as ScrollableControl).VerticalScroll.Value;181 }182 else if (control is TreeView)183 {184 barV.Maximum = GetTreeNodeMaxY(control as TreeView);185 barV.Value = https://www.cnblogs.com/bfyx/p/(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 = https://www.cnblogs.com/bfyx/p/(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 else220 {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 =https://www.cnblogs.com/bfyx/p/= 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\u7406275 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 = https://www.cnblogs.com/bfyx/p/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 = https://www.cnblogs.com/bfyx/p/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 #endregion343 344 #region TextBox處理 English:TextBox Processing345 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 = https://www.cnblogs.com/bfyx/p/(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 = https://www.cnblogs.com/bfyx/p/(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 =https://www.cnblogs.com/bfyx/p/ m_lstVCache[txt].Maximum;411 else412 m_lstVCache[txt].Value += height;413 }414 else415 {416 if (m_lstVCache[txt].Value - height < 0)417 m_lstVCache[txt].Value = https://www.cnblogs.com/bfyx/p/0;418 else419 m_lstVCache[txt].Value -= height;420 }421 }422 }423 }424 #endregion425 }426 }View Code
代碼就這些了
使用的時候,只需要在界面上添加組件ScrollbarComponent即可
最后的話
如果你喜歡的話,請到 https://gitee.com/kwwwvagaa/net_winform_custom_control 點個星 星吧
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/6451.html
標籤:WinForm

