入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
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:623128629@qq.com
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即可