欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

(六十九)c#Winform自定义控件-垂直滚动条

程序员文章站 2022-08-05 23:14:34
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。 GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:https://gitee.com/kwwwvagaa/net_winform_custom_contr ......

前提

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

github:https://github.com/kwwwvagaa/netwinformcontrol

码云:

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

欢迎前来交流探讨: 企鹅群568015492 

麻烦博客下方点个【推荐】,谢谢

nuget

install-package hzh_controls

目录

用处及效果

(六十九)c#Winform自定义控件-垂直滚动条

 

 (六十九)c#Winform自定义控件-垂直滚动条

 

 目前支持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即可

最后的话

如果你喜欢的话,请到  点个星 星吧