(六十九)c#Winform自定义控件-垂直滚动条
程序员文章站
2022-08-05 23:14:28
前提 入行已经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
目录
用处及效果
目前支持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即可
最后的话
如果你喜欢的话,请到 点个星 星吧
上一篇: (六十九)c#Winform自定义控件-垂直滚动条
下一篇: C#服务器全面讲解与制作