官网

http://www.hzhcontrols.com

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

GitHub:https://github.com/kwwwvagaa/NetWinformControl

码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 企鹅群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 = 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 }

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 = (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 }

View Code

代码就这些了

 

使用的时候,只需要在界面上添加组件ScrollbarComponent即可

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧

版权声明:本文为bfyx原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/bfyx/p/11550897.html