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


    官网

    http://www.hzhcontrols.com

    前提

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

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

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

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

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

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

    NuGet

    Install-Package HZH_Controls

    目录

    https://www.cnblogs.com/bfyx/p/11364884.html

    用处及效果

     

     目前支持ScrollableControl,TreeView,TextBox的滚动条,只需要在相应的界面上添加组件ScrollbarComponent即可

    准备工作

    用到了(一)c#Winform自定义控件-基类控件 ,如果你还不了解,可以先去看一下

    自定义滚动条有2种方式,1:拦截windows消息,重绘,2:做一个新的,盖上去挡着,这里我们采用的是第二种。

    开始

    添加一个类UCVScrollbar,继承UCControlBase

    一些属性

      1  /// <summary>
      2         /// The mo large change
      3         /// </summary>
      4         protected int moLargeChange = 10;
      5         /// <summary>
      6         /// The mo small change
      7         /// </summary>
      8         protected int moSmallChange = 1;
      9         /// <summary>
     10         /// The mo minimum
     11         /// </summary>
     12         protected int moMinimum = 0;
     13         /// <summary>
     14         /// The mo maximum
     15         /// </summary>
     16         protected int moMaximum = 100;
     17         /// <summary>
     18         /// The mo value
     19         /// </summary>
     20         protected int moValue = 0;
     21         /// <summary>
     22         /// The n click point
     23         /// </summary>
     24         private int nClickPoint;
     25         /// <summary>
     26         /// The mo thumb top
     27         /// </summary>
     28         protected int moThumbTop = 0;
     29         /// <summary>
     30         /// The mo automatic size
     31         /// </summary>
     32         protected bool moAutoSize = false;
     33         /// <summary>
     34         /// The mo thumb down
     35         /// </summary>
     36         private bool moThumbDown = false;
     37         /// <summary>
     38         /// The mo thumb dragging
     39         /// </summary>
     40         private bool moThumbDragging = false;
     41         /// <summary>
     42         /// Occurs when [scroll].
     43         /// </summary>
     44         public new event EventHandler Scroll = null;
     45         /// <summary>
     46         /// Occurs when [value changed].
     47         /// </summary>
     48         public event EventHandler ValueChanged = null;
     49 
     50         /// <summary>
     51         /// The BTN height
     52         /// </summary>
     53         private int btnHeight = 18;
     54         /// <summary>
     55         /// The m int thumb minimum height
     56         /// </summary>
     57         private int m_intThumbMinHeight = 15;
     58 
     59         /// <summary>
     60         /// Gets or sets the height of the BTN.
     61         /// </summary>
     62         /// <value>The height of the BTN.</value>
     63         public int BtnHeight
     64         {
     65             get { return btnHeight; }
     66             set { btnHeight = value; }
     67         }
     68         /// <summary>
     69         /// Gets or sets the large change.
     70         /// </summary>
     71         /// <value>The large change.</value>
     72         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("LargeChange")]
     73         public int LargeChange
     74         {
     75             get { return moLargeChange; }
     76             set
     77             {
     78                 moLargeChange = value;
     79                 Invalidate();
     80             }
     81         }
     82 
     83         /// <summary>
     84         /// Gets or sets the small change.
     85         /// </summary>
     86         /// <value>The small change.</value>
     87         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("SmallChange")]
     88         public int SmallChange
     89         {
     90             get { return moSmallChange; }
     91             set
     92             {
     93                 moSmallChange = value;
     94                 Invalidate();
     95             }
     96         }
     97 
     98         /// <summary>
     99         /// Gets or sets the minimum.
    100         /// </summary>
    101         /// <value>The minimum.</value>
    102         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Minimum")]
    103         public int Minimum
    104         {
    105             get { return moMinimum; }
    106             set
    107             {
    108                 moMinimum = value;
    109                 Invalidate();
    110             }
    111         }
    112 
    113         /// <summary>
    114         /// Gets or sets the maximum.
    115         /// </summary>
    116         /// <value>The maximum.</value>
    117         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Maximum")]
    118         public int Maximum
    119         {
    120             get { return moMaximum; }
    121             set
    122             {
    123                 moMaximum = value;
    124                 Invalidate();
    125             }
    126         }
    127 
    128         /// <summary>
    129         /// Gets or sets the value.
    130         /// </summary>
    131         /// <value>The value.</value>
    132         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Value")]
    133         public int Value
    134         {
    135             get { return moValue; }
    136             set
    137             {
    138                 moValue = value;
    139 
    140                 int nTrackHeight = (this.Height - btnHeight * 2);
    141                 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
    142                 int nThumbHeight = (int)fThumbHeight;
    143 
    144                 if (nThumbHeight > nTrackHeight)
    145                 {
    146                     nThumbHeight = nTrackHeight;
    147                     fThumbHeight = nTrackHeight;
    148                 }
    149                 if (nThumbHeight < m_intThumbMinHeight)
    150                 {
    151                     nThumbHeight = m_intThumbMinHeight;
    152                     fThumbHeight = m_intThumbMinHeight;
    153                 }
    154 
    155                 //figure out value
    156                 int nPixelRange = nTrackHeight - nThumbHeight;
    157                 int nRealRange = (Maximum - Minimum) - LargeChange;
    158                 float fPerc = 0.0f;
    159                 if (nRealRange != 0)
    160                 {
    161                     fPerc = (float)moValue / (float)nRealRange;
    162 
    163                 }
    164 
    165                 float fTop = fPerc * nPixelRange;
    166                 moThumbTop = (int)fTop;
    167 
    168 
    169                 Invalidate();
    170             }
    171         }
    172 
    173         /// <summary>
    174         /// Gets or sets a value indicating whether [automatic size].
    175         /// </summary>
    176         /// <value><c>true</c> if [automatic size]; otherwise, <c>false</c>.</value>
    177         public override bool AutoSize
    178         {
    179             get
    180             {
    181                 return base.AutoSize;
    182             }
    183             set
    184             {
    185                 base.AutoSize = value;
    186                 if (base.AutoSize)
    187                 {
    188                     this.Width = 15;
    189                 }
    190             }
    191         }
    192 
    193         /// <summary>
    194         /// The thumb color
    195         /// </summary>
    196         private Color thumbColor = Color.FromArgb(255, 77, 58);
    197 
    198         /// <summary>
    199         /// Gets or sets the color of the thumb.
    200         /// </summary>
    201         /// <value>The color of the thumb.</value>
    202         public Color ThumbColor
    203         {
    204             get { return thumbColor; }
    205             set { thumbColor = value; }
    206         }

    重绘

     1  protected override void OnPaint(PaintEventArgs e)
     2         {
     3             base.OnPaint(e);
     4             e.Graphics.SetGDIHigh();
     5 
     6             //draw thumb
     7             int nTrackHeight = (this.Height - btnHeight * 2);
     8             float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
     9             int nThumbHeight = (int)fThumbHeight;
    10 
    11             if (nThumbHeight > nTrackHeight)
    12             {
    13                 nThumbHeight = nTrackHeight;
    14                 fThumbHeight = nTrackHeight;
    15             }
    16             if (nThumbHeight < m_intThumbMinHeight)
    17             {
    18                 nThumbHeight = m_intThumbMinHeight;
    19                 fThumbHeight = m_intThumbMinHeight;
    20             }
    21             int nTop = moThumbTop;
    22             nTop += btnHeight;
    23             e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(1, nTop, this.Width - 3, nThumbHeight).CreateRoundedRectanglePath(this.ConerRadius));
    24 
    25             ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, btnHeight - Math.Min(5, this.Width / 2)), Math.Min(5, this.Width / 2), GraphDirection.Upward);
    26             ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, this.Height - (btnHeight - Math.Min(5, this.Width / 2))), Math.Min(5, this.Width / 2), GraphDirection.Downward);
    27 
    28         }

    处理下鼠标事件

      1  /// <summary>
      2         /// Handles the MouseDown event of the CustomScrollbar control.
      3         /// </summary>
      4         /// <param name="sender">The source of the event.</param>
      5         /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
      6         private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e)
      7         {
      8             Point ptPoint = this.PointToClient(Cursor.Position);
      9             int nTrackHeight = (this.Height - btnHeight * 2);
     10             float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
     11             int nThumbHeight = (int)fThumbHeight;
     12 
     13             if (nThumbHeight > nTrackHeight)
     14             {
     15                 nThumbHeight = nTrackHeight;
     16                 fThumbHeight = nTrackHeight;
     17             }
     18             if (nThumbHeight < m_intThumbMinHeight)
     19             {
     20                 nThumbHeight = m_intThumbMinHeight;
     21                 fThumbHeight = m_intThumbMinHeight;
     22             }
     23 
     24             int nTop = moThumbTop;
     25             nTop += btnHeight;
     26 
     27 
     28             Rectangle thumbrect = new Rectangle(new Point(1, nTop), new Size(this.Width - 2, nThumbHeight));
     29             if (thumbrect.Contains(ptPoint))
     30             {
     31 
     32                 //hit the thumb
     33                 nClickPoint = (ptPoint.Y - nTop);
     34                 //MessageBox.Show(Convert.ToString((ptPoint.Y - nTop)));
     35                 this.moThumbDown = true;
     36             }
     37 
     38             Rectangle uparrowrect = new Rectangle(new Point(1, 0), new Size(this.Width, btnHeight));
     39             if (uparrowrect.Contains(ptPoint))
     40             {
     41 
     42                 int nRealRange = (Maximum - Minimum) - LargeChange;
     43                 int nPixelRange = (nTrackHeight - nThumbHeight);
     44                 if (nRealRange > 0)
     45                 {
     46                     if (nPixelRange > 0)
     47                     {
     48                         if ((moThumbTop - SmallChange) < 0)
     49                             moThumbTop = 0;
     50                         else
     51                             moThumbTop -= SmallChange;
     52 
     53                         //figure out value
     54                         float fPerc = (float)moThumbTop / (float)nPixelRange;
     55                         float fValue = fPerc * (Maximum - LargeChange);
     56 
     57                         moValue = (int)fValue;
     58 
     59                         if (ValueChanged != null)
     60                             ValueChanged(this, new EventArgs());
     61 
     62                         if (Scroll != null)
     63                             Scroll(this, new EventArgs());
     64 
     65                         Invalidate();
     66                     }
     67                 }
     68             }
     69 
     70             Rectangle downarrowrect = new Rectangle(new Point(1, btnHeight + nTrackHeight), new Size(this.Width, btnHeight));
     71             if (downarrowrect.Contains(ptPoint))
     72             {
     73                 int nRealRange = (Maximum - Minimum) - LargeChange;
     74                 int nPixelRange = (nTrackHeight - nThumbHeight);
     75                 if (nRealRange > 0)
     76                 {
     77                     if (nPixelRange > 0)
     78                     {
     79                         if ((moThumbTop + SmallChange) > nPixelRange)
     80                             moThumbTop = nPixelRange;
     81                         else
     82                             moThumbTop += SmallChange;
     83 
     84                         //figure out value
     85                         float fPerc = (float)moThumbTop / (float)nPixelRange;
     86                         float fValue = fPerc * (Maximum - LargeChange);
     87 
     88                         moValue = (int)fValue;
     89 
     90                         if (ValueChanged != null)
     91                             ValueChanged(this, new EventArgs());
     92 
     93                         if (Scroll != null)
     94                             Scroll(this, new EventArgs());
     95 
     96                         Invalidate();
     97                     }
     98                 }
     99             }
    100         }
    101 
    102         /// <summary>
    103         /// Handles the MouseUp event of the CustomScrollbar control.
    104         /// </summary>
    105         /// <param name="sender">The source of the event.</param>
    106         /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
    107         private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e)
    108         {
    109             this.moThumbDown = false;
    110             this.moThumbDragging = false;
    111         }
    112 
    113         /// <summary>
    114         /// Moves the thumb.
    115         /// </summary>
    116         /// <param name="y">The y.</param>
    117         private void MoveThumb(int y)
    118         {
    119             int nRealRange = Maximum - Minimum;
    120             int nTrackHeight = (this.Height - btnHeight * 2);
    121             float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
    122             int nThumbHeight = (int)fThumbHeight;
    123 
    124             if (nThumbHeight > nTrackHeight)
    125             {
    126                 nThumbHeight = nTrackHeight;
    127                 fThumbHeight = nTrackHeight;
    128             }
    129             if (nThumbHeight < m_intThumbMinHeight)
    130             {
    131                 nThumbHeight = m_intThumbMinHeight;
    132                 fThumbHeight = m_intThumbMinHeight;
    133             }
    134 
    135             int nSpot = nClickPoint;
    136 
    137             int nPixelRange = (nTrackHeight - nThumbHeight);
    138             if (moThumbDown && nRealRange > 0)
    139             {
    140                 if (nPixelRange > 0)
    141                 {
    142                     int nNewThumbTop = y - (btnHeight + nSpot);
    143 
    144                     if (nNewThumbTop < 0)
    145                     {
    146                         moThumbTop = nNewThumbTop = 0;
    147                     }
    148                     else if (nNewThumbTop > nPixelRange)
    149                     {
    150                         moThumbTop = nNewThumbTop = nPixelRange;
    151                     }
    152                     else
    153                     {
    154                         moThumbTop = y - (btnHeight + nSpot);
    155                     }
    156 
    157 
    158                     float fPerc = (float)moThumbTop / (float)nPixelRange;
    159                     float fValue = fPerc * (Maximum - LargeChange);
    160                     moValue = (int)fValue;
    161 
    162                     Application.DoEvents();
    163 
    164                     Invalidate();
    165                 }
    166             }
    167         }
    168 
    169         /// <summary>
    170         /// Handles the MouseMove event of the CustomScrollbar control.
    171         /// </summary>
    172         /// <param name="sender">The source of the event.</param>
    173         /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
    174         private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e)
    175         {
    176             if (!moThumbDown)
    177                 return;
    178 
    179             if (moThumbDown == true)
    180             {
    181                 this.moThumbDragging = true;
    182             }
    183 
    184             if (this.moThumbDragging)
    185             {
    186                 MoveThumb(e.Y);
    187             }
    188 
    189             if (ValueChanged != null)
    190                 ValueChanged(this, new EventArgs());
    191 
    192             if (Scroll != null)
    193                 Scroll(this, new EventArgs());
    194         }

    完整代码

      1 // ***********************************************************************
      2 // Assembly         : HZH_Controls
      3 // Created          : 2019-09-19
      4 //
      5 // ***********************************************************************
      6 // <copyright file="UCVScrollbar.cs">
      7 //     Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
      8 // </copyright>
      9 //
     10 // Blog: https://www.cnblogs.com/bfyx
     11 // GitHub:https://github.com/kwwwvagaa/NetWinformControl
     12 // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
     13 //
     14 // If you use this code, please keep this note.
     15 // ***********************************************************************
     16 using System;
     17 using System.Collections.Generic;
     18 using System.ComponentModel;
     19 using System.Drawing;
     20 using System.Data;
     21 using System.Text;
     22 using System.Windows.Forms;
     23 using System.Windows.Forms.Design;
     24 using System.Diagnostics;
     25 
     26 
     27 namespace HZH_Controls.Controls
     28 {
     29 
     30     /// <summary>
     31     /// Class UCVScrollbar.
     32     /// Implements the <see cref="HZH_Controls.Controls.UCControlBase" />
     33     /// </summary>
     34     /// <seealso cref="HZH_Controls.Controls.UCControlBase" />
     35     [Designer(typeof(ScrollbarControlDesigner))]
     36     [DefaultEvent("Scroll")]
     37     public class UCVScrollbar : UCControlBase
     38     {        
     39         /// <summary>
     40         /// The mo large change
     41         /// </summary>
     42         protected int moLargeChange = 10;
     43         /// <summary>
     44         /// The mo small change
     45         /// </summary>
     46         protected int moSmallChange = 1;
     47         /// <summary>
     48         /// The mo minimum
     49         /// </summary>
     50         protected int moMinimum = 0;
     51         /// <summary>
     52         /// The mo maximum
     53         /// </summary>
     54         protected int moMaximum = 100;
     55         /// <summary>
     56         /// The mo value
     57         /// </summary>
     58         protected int moValue = 0;
     59         /// <summary>
     60         /// The n click point
     61         /// </summary>
     62         private int nClickPoint;
     63         /// <summary>
     64         /// The mo thumb top
     65         /// </summary>
     66         protected int moThumbTop = 0;
     67         /// <summary>
     68         /// The mo automatic size
     69         /// </summary>
     70         protected bool moAutoSize = false;
     71         /// <summary>
     72         /// The mo thumb down
     73         /// </summary>
     74         private bool moThumbDown = false;
     75         /// <summary>
     76         /// The mo thumb dragging
     77         /// </summary>
     78         private bool moThumbDragging = false;
     79         /// <summary>
     80         /// Occurs when [scroll].
     81         /// </summary>
     82         public new event EventHandler Scroll = null;
     83         /// <summary>
     84         /// Occurs when [value changed].
     85         /// </summary>
     86         public event EventHandler ValueChanged = null;
     87 
     88         /// <summary>
     89         /// The BTN height
     90         /// </summary>
     91         private int btnHeight = 18;
     92         /// <summary>
     93         /// The m int thumb minimum height
     94         /// </summary>
     95         private int m_intThumbMinHeight = 15;
     96 
     97         /// <summary>
     98         /// Gets or sets the height of the BTN.
     99         /// </summary>
    100         /// <value>The height of the BTN.</value>
    101         public int BtnHeight
    102         {
    103             get { return btnHeight; }
    104             set { btnHeight = value; }
    105         }
    106         /// <summary>
    107         /// Gets or sets the large change.
    108         /// </summary>
    109         /// <value>The large change.</value>
    110         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("LargeChange")]
    111         public int LargeChange
    112         {
    113             get { return moLargeChange; }
    114             set
    115             {
    116                 moLargeChange = value;
    117                 Invalidate();
    118             }
    119         }
    120 
    121         /// <summary>
    122         /// Gets or sets the small change.
    123         /// </summary>
    124         /// <value>The small change.</value>
    125         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("SmallChange")]
    126         public int SmallChange
    127         {
    128             get { return moSmallChange; }
    129             set
    130             {
    131                 moSmallChange = value;
    132                 Invalidate();
    133             }
    134         }
    135 
    136         /// <summary>
    137         /// Gets or sets the minimum.
    138         /// </summary>
    139         /// <value>The minimum.</value>
    140         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Minimum")]
    141         public int Minimum
    142         {
    143             get { return moMinimum; }
    144             set
    145             {
    146                 moMinimum = value;
    147                 Invalidate();
    148             }
    149         }
    150 
    151         /// <summary>
    152         /// Gets or sets the maximum.
    153         /// </summary>
    154         /// <value>The maximum.</value>
    155         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Maximum")]
    156         public int Maximum
    157         {
    158             get { return moMaximum; }
    159             set
    160             {
    161                 moMaximum = value;
    162                 Invalidate();
    163             }
    164         }
    165 
    166         /// <summary>
    167         /// Gets or sets the value.
    168         /// </summary>
    169         /// <value>The value.</value>
    170         [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Value")]
    171         public int Value
    172         {
    173             get { return moValue; }
    174             set
    175             {
    176                 moValue = value;
    177 
    178                 int nTrackHeight = (this.Height - btnHeight * 2);
    179                 float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
    180                 int nThumbHeight = (int)fThumbHeight;
    181 
    182                 if (nThumbHeight > nTrackHeight)
    183                 {
    184                     nThumbHeight = nTrackHeight;
    185                     fThumbHeight = nTrackHeight;
    186                 }
    187                 if (nThumbHeight < m_intThumbMinHeight)
    188                 {
    189                     nThumbHeight = m_intThumbMinHeight;
    190                     fThumbHeight = m_intThumbMinHeight;
    191                 }
    192 
    193                 //figure out value
    194                 int nPixelRange = nTrackHeight - nThumbHeight;
    195                 int nRealRange = (Maximum - Minimum) - LargeChange;
    196                 float fPerc = 0.0f;
    197                 if (nRealRange != 0)
    198                 {
    199                     fPerc = (float)moValue / (float)nRealRange;
    200 
    201                 }
    202 
    203                 float fTop = fPerc * nPixelRange;
    204                 moThumbTop = (int)fTop;
    205 
    206 
    207                 Invalidate();
    208             }
    209         }
    210 
    211         /// <summary>
    212         /// Gets or sets a value indicating whether [automatic size].
    213         /// </summary>
    214         /// <value><c>true</c> if [automatic size]; otherwise, <c>false</c>.</value>
    215         public override bool AutoSize
    216         {
    217             get
    218             {
    219                 return base.AutoSize;
    220             }
    221             set
    222             {
    223                 base.AutoSize = value;
    224                 if (base.AutoSize)
    225                 {
    226                     this.Width = 15;
    227                 }
    228             }
    229         }
    230 
    231         /// <summary>
    232         /// The thumb color
    233         /// </summary>
    234         private Color thumbColor = Color.FromArgb(255, 77, 58);
    235 
    236         /// <summary>
    237         /// Gets or sets the color of the thumb.
    238         /// </summary>
    239         /// <value>The color of the thumb.</value>
    240         public Color ThumbColor
    241         {
    242             get { return thumbColor; }
    243             set { thumbColor = value; }
    244         }
    245 
    246         /// <summary>
    247         /// Initializes a new instance of the <see cref="UCVScrollbar"/> class.
    248         /// </summary>
    249         public UCVScrollbar()
    250         {
    251             InitializeComponent();
    252             ConerRadius = 2;
    253             FillColor = Color.FromArgb(239, 239, 239);
    254             IsShowRect = false;
    255             IsRadius = true;
    256             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
    257             this.SetStyle(ControlStyles.DoubleBuffer, true);
    258             this.SetStyle(ControlStyles.ResizeRedraw, true);
    259             this.SetStyle(ControlStyles.Selectable, true);
    260             this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    261             this.SetStyle(ControlStyles.UserPaint, true);
    262         }
    263 
    264 
    265 
    266 
    267         /// <summary>
    268         /// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 事件。
    269         /// </summary>
    270         /// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" /></param>
    271         protected override void OnPaint(PaintEventArgs e)
    272         {
    273             base.OnPaint(e);
    274             e.Graphics.SetGDIHigh();
    275 
    276             //draw thumb
    277             int nTrackHeight = (this.Height - btnHeight * 2);
    278             float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
    279             int nThumbHeight = (int)fThumbHeight;
    280 
    281             if (nThumbHeight > nTrackHeight)
    282             {
    283                 nThumbHeight = nTrackHeight;
    284                 fThumbHeight = nTrackHeight;
    285             }
    286             if (nThumbHeight < m_intThumbMinHeight)
    287             {
    288                 nThumbHeight = m_intThumbMinHeight;
    289                 fThumbHeight = m_intThumbMinHeight;
    290             }
    291             int nTop = moThumbTop;
    292             nTop += btnHeight;
    293             e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(1, nTop, this.Width - 3, nThumbHeight).CreateRoundedRectanglePath(this.ConerRadius));
    294 
    295             ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, btnHeight - Math.Min(5, this.Width / 2)), Math.Min(5, this.Width / 2), GraphDirection.Upward);
    296             ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / 2, this.Height - (btnHeight - Math.Min(5, this.Width / 2))), Math.Min(5, this.Width / 2), GraphDirection.Downward);
    297 
    298         }
    299 
    300         /// <summary>
    301         /// Initializes the component.
    302         /// </summary>
    303         private void InitializeComponent()
    304         {
    305             this.SuspendLayout();
    306             // 
    307             // UCVScrollbar
    308             // 
    309             this.MinimumSize = new System.Drawing.Size(10, 0);
    310             this.Name = "UCVScrollbar";
    311             this.Size = new System.Drawing.Size(18, 150);
    312             this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseDown);
    313             this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseMove);
    314             this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseUp);
    315             this.ResumeLayout(false);
    316 
    317         }
    318 
    319         /// <summary>
    320         /// Handles the MouseDown event of the CustomScrollbar control.
    321         /// </summary>
    322         /// <param name="sender">The source of the event.</param>
    323         /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
    324         private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e)
    325         {
    326             Point ptPoint = this.PointToClient(Cursor.Position);
    327             int nTrackHeight = (this.Height - btnHeight * 2);
    328             float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
    329             int nThumbHeight = (int)fThumbHeight;
    330 
    331             if (nThumbHeight > nTrackHeight)
    332             {
    333                 nThumbHeight = nTrackHeight;
    334                 fThumbHeight = nTrackHeight;
    335             }
    336             if (nThumbHeight < m_intThumbMinHeight)
    337             {
    338                 nThumbHeight = m_intThumbMinHeight;
    339                 fThumbHeight = m_intThumbMinHeight;
    340             }
    341 
    342             int nTop = moThumbTop;
    343             nTop += btnHeight;
    344 
    345 
    346             Rectangle thumbrect = new Rectangle(new Point(1, nTop), new Size(this.Width - 2, nThumbHeight));
    347             if (thumbrect.Contains(ptPoint))
    348             {
    349 
    350                 //hit the thumb
    351                 nClickPoint = (ptPoint.Y - nTop);
    352                 //MessageBox.Show(Convert.ToString((ptPoint.Y - nTop)));
    353                 this.moThumbDown = true;
    354             }
    355 
    356             Rectangle uparrowrect = new Rectangle(new Point(1, 0), new Size(this.Width, btnHeight));
    357             if (uparrowrect.Contains(ptPoint))
    358             {
    359 
    360                 int nRealRange = (Maximum - Minimum) - LargeChange;
    361                 int nPixelRange = (nTrackHeight - nThumbHeight);
    362                 if (nRealRange > 0)
    363                 {
    364                     if (nPixelRange > 0)
    365                     {
    366                         if ((moThumbTop - SmallChange) < 0)
    367                             moThumbTop = 0;
    368                         else
    369                             moThumbTop -= SmallChange;
    370 
    371                         //figure out value
    372                         float fPerc = (float)moThumbTop / (float)nPixelRange;
    373                         float fValue = fPerc * (Maximum - LargeChange);
    374 
    375                         moValue = (int)fValue;
    376 
    377                         if (ValueChanged != null)
    378                             ValueChanged(this, new EventArgs());
    379 
    380                         if (Scroll != null)
    381                             Scroll(this, new EventArgs());
    382 
    383                         Invalidate();
    384                     }
    385                 }
    386             }
    387 
    388             Rectangle downarrowrect = new Rectangle(new Point(1, btnHeight + nTrackHeight), new Size(this.Width, btnHeight));
    389             if (downarrowrect.Contains(ptPoint))
    390             {
    391                 int nRealRange = (Maximum - Minimum) - LargeChange;
    392                 int nPixelRange = (nTrackHeight - nThumbHeight);
    393                 if (nRealRange > 0)
    394                 {
    395                     if (nPixelRange > 0)
    396                     {
    397                         if ((moThumbTop + SmallChange) > nPixelRange)
    398                             moThumbTop = nPixelRange;
    399                         else
    400                             moThumbTop += SmallChange;
    401 
    402                         //figure out value
    403                         float fPerc = (float)moThumbTop / (float)nPixelRange;
    404                         float fValue = fPerc * (Maximum - LargeChange);
    405 
    406                         moValue = (int)fValue;
    407 
    408                         if (ValueChanged != null)
    409                             ValueChanged(this, new EventArgs());
    410 
    411                         if (Scroll != null)
    412                             Scroll(this, new EventArgs());
    413 
    414                         Invalidate();
    415                     }
    416                 }
    417             }
    418         }
    419 
    420         /// <summary>
    421         /// Handles the MouseUp event of the CustomScrollbar control.
    422         /// </summary>
    423         /// <param name="sender">The source of the event.</param>
    424         /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
    425         private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e)
    426         {
    427             this.moThumbDown = false;
    428             this.moThumbDragging = false;
    429         }
    430 
    431         /// <summary>
    432         /// Moves the thumb.
    433         /// </summary>
    434         /// <param name="y">The y.</param>
    435         private void MoveThumb(int y)
    436         {
    437             int nRealRange = Maximum - Minimum;
    438             int nTrackHeight = (this.Height - btnHeight * 2);
    439             float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
    440             int nThumbHeight = (int)fThumbHeight;
    441 
    442             if (nThumbHeight > nTrackHeight)
    443             {
    444                 nThumbHeight = nTrackHeight;
    445                 fThumbHeight = nTrackHeight;
    446             }
    447             if (nThumbHeight < m_intThumbMinHeight)
    448             {
    449                 nThumbHeight = m_intThumbMinHeight;
    450                 fThumbHeight = m_intThumbMinHeight;
    451             }
    452 
    453             int nSpot = nClickPoint;
    454 
    455             int nPixelRange = (nTrackHeight - nThumbHeight);
    456             if (moThumbDown && nRealRange > 0)
    457             {
    458                 if (nPixelRange > 0)
    459                 {
    460                     int nNewThumbTop = y - (btnHeight + nSpot);
    461 
    462                     if (nNewThumbTop < 0)
    463                     {
    464                         moThumbTop = nNewThumbTop = 0;
    465                     }
    466                     else if (nNewThumbTop > nPixelRange)
    467                     {
    468                         moThumbTop = nNewThumbTop = nPixelRange;
    469                     }
    470                     else
    471                     {
    472                         moThumbTop = y - (btnHeight + nSpot);
    473                     }
    474 
    475 
    476                     float fPerc = (float)moThumbTop / (float)nPixelRange;
    477                     float fValue = fPerc * (Maximum - LargeChange);
    478                     moValue = (int)fValue;
    479 
    480                     Application.DoEvents();
    481 
    482                     Invalidate();
    483                 }
    484             }
    485         }
    486 
    487         /// <summary>
    488         /// Handles the MouseMove event of the CustomScrollbar control.
    489         /// </summary>
    490         /// <param name="sender">The source of the event.</param>
    491         /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
    492         private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e)
    493         {
    494             if (!moThumbDown)
    495                 return;
    496 
    497             if (moThumbDown == true)
    498             {
    499                 this.moThumbDragging = true;
    500             }
    501 
    502             if (this.moThumbDragging)
    503             {
    504                 MoveThumb(e.Y);
    505             }
    506 
    507             if (ValueChanged != null)
    508                 ValueChanged(this, new EventArgs());
    509 
    510             if (Scroll != null)
    511                 Scroll(this, new EventArgs());
    512         }
    513 
    514     }
    515 
    516     /// <summary>
    517     /// Class ScrollbarControlDesigner.
    518     /// Implements the <see cref="System.Windows.Forms.Design.ControlDesigner" />
    519     /// </summary>
    520     /// <seealso cref="System.Windows.Forms.Design.ControlDesigner" />
    521     internal class ScrollbarControlDesigner : System.Windows.Forms.Design.ControlDesigner
    522     {
    523         /// <summary>
    524         /// 获取指示组件的移动功能的选择规则。
    525         /// </summary>
    526         /// <value>The selection rules.</value>
    527         public override SelectionRules SelectionRules
    528         {
    529             get
    530             {
    531                 SelectionRules selectionRules = base.SelectionRules;
    532                 PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(this.Component)["AutoSize"];
    533                 if (propDescriptor != null)
    534                 {
    535                     bool autoSize = (bool)propDescriptor.GetValue(this.Component);
    536                     if (autoSize)
    537                     {
    538                         selectionRules = SelectionRules.Visible | SelectionRules.Moveable | SelectionRules.BottomSizeable | SelectionRules.TopSizeable;
    539                     }
    540                     else
    541                     {
    542                         selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable;
    543                     }
    544                 }
    545                 return selectionRules;
    546             }
    547         }
    548     }
    549 }
    View Code

    为了方便使用,我们添加一个组件

    新增类ScrollbarComponent,继承 Component, IExtenderProvider

    实现接口方法

     1  public bool CanExtend(object extendee)
     2         {
     3             if (extendee is ScrollableControl)
     4             {
     5                 ScrollableControl control = (ScrollableControl)extendee;
     6                 if (control.AutoScroll == true)
     7                 {
     8                     return true;
     9                 }
    10             }
    11             else if (extendee is TreeView)
    12             {
    13                 TreeView control = (TreeView)extendee;
    14                 if (control.Scrollable)
    15                 {
    16                     return true;
    17                 }
    18             }
    19             else if (extendee is TextBox)
    20             {
    21                 TextBox control = (TextBox)extendee;
    22                 if (control.Multiline && control.ScrollBars != ScrollBars.None)
    23                 {
    24                     return true;
    25                 }
    26             }
    27             return false;
    28         }

    扩展控件属性

     1   [Browsable(true), Category("自定义属性"), Description("是否使用自定义滚动条"), DisplayName("UserCustomScrollbar"), Localizable(true)]
     2         public bool GetUserCustomScrollbar(Control control)
     3         {
     4             return m_blnUserCustomScrollbar;
     5         }
     6 
     7         public void SetUserCustomScrollbar(Control control, bool blnUserCustomScrollbar)
     8         {
     9             m_blnUserCustomScrollbar = blnUserCustomScrollbar;
    10             control.VisibleChanged += control_VisibleChanged;
    11             control.SizeChanged += control_SizeChanged;
    12             control.LocationChanged += control_LocationChanged;
    13             control.Disposed += control_Disposed;
    14             
    15             if (control is TreeView)
    16             {
    17                 TreeView tv = (TreeView)control;
    18                 tv.MouseWheel += tv_MouseWheel;                
    19                 tv.AfterSelect += tv_AfterSelect;
    20                 tv.AfterExpand += tv_AfterExpand;
    21                 tv.AfterCollapse += tv_AfterCollapse;
    22             }
    23             else if (control is TextBox)
    24             {
    25                 TextBox txt = (TextBox)control;
    26                 txt.MouseWheel += txt_MouseWheel;
    27                 txt.TextChanged += txt_TextChanged;
    28                
    29                 txt.KeyDown += txt_KeyDown;
    30             }
    31             control_SizeChanged(control, null);
    32         }
    33        

    处理一下控件什么时候添加滚动条,什么时候移除滚动条,以及滚动条位置大小的改变等

      1  void control_Disposed(object sender, EventArgs e)
      2         {
      3             Control control = (Control)sender;
      4             if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
      5             {
      6                 m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
      7                 m_lstVCache.Remove(control);
      8             }
      9         }
     10 
     11         void control_LocationChanged(object sender, EventArgs e)
     12         {
     13             ResetVScrollLocation(sender);
     14         }
     15 
     16         void control_SizeChanged(object sender, EventArgs e)
     17         {
     18             if (ControlHelper.IsDesignMode())
     19             {
     20                 return;
     21             }
     22             else
     23             {
     24                 var control = sender as Control;
     25 
     26                 bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0;
     27                 bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0;
     28                 if (blnHasVScrollbar)
     29                 {
     30                     if (!m_lstVCache.ContainsKey(control))
     31                     {
     32                         if (control.Parent != null)
     33                         {
     34                             UCVScrollbar barV = new UCVScrollbar();
     35                             barV.Scroll += barV_Scroll;
     36                             m_lstVCache[control] = barV;
     37                             if (blnHasHScrollbar)
     38                             {
     39                                 barV.Height = control.Height - barV.Width - 2;
     40                             }
     41                             else
     42                             {
     43                                 barV.Height = control.Height - 2;
     44                             }
     45                             SetVMaxNum(control);
     46                             barV.Location = new System.Drawing.Point(control.Right - barV.Width - 1, control.Top + 1);
     47                             control.Parent.Controls.Add(barV);
     48                             int intControlIndex = control.Parent.Controls.GetChildIndex(control);
     49                             control.Parent.Controls.SetChildIndex(barV, intControlIndex);
     50                         }
     51                     }
     52                     else
     53                     {
     54                         SetVMaxNum(control);
     55                     }
     56                 }
     57                 else
     58                 {
     59                     if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
     60                     {
     61                         m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
     62                         m_lstVCache.Remove(control);
     63                     }
     64                 }
     65 
     66                 //if (blnHasHScrollbar)
     67                 //{
     68                 //    if (control.Parent != null)
     69                 //    {
     70 
     71                 //    }
     72                 //}
     73                 //else
     74                 //{
     75                 //    if (m_lstHCache.ContainsKey(control))
     76                 //    {
     77                 //        if (m_lstHCache[control].Visible)
     78                 //        {
     79                 //            m_lstHCache[control].Parent.Controls.Remove(m_lstHCache[control]);
     80                 //        }
     81                 //    }
     82                 //}
     83             }
     84             ResetVScrollLocation(sender);
     85         }
     86 
     87         private void SetVMaxNum(Control control)
     88         {
     89             if (!m_lstVCache.ContainsKey(control))
     90                 return;
     91             UCVScrollbar barV = m_lstVCache[control];
     92             if (control is ScrollableControl)
     93             {
     94                 barV.Maximum = (control as ScrollableControl).VerticalScroll.Maximum;
     95                 barV.Value = (control as ScrollableControl).VerticalScroll.Value;
     96             }
     97             else if (control is TreeView)
     98             {
     99                 barV.Maximum = GetTreeNodeMaxY(control as TreeView);
    100                 barV.Value = (control as TreeView).AutoScrollOffset.Y;
    101             }
    102             else if (control is TextBox)
    103             {
    104                 TextBox txt = (TextBox)control;
    105                 int intTxtMaxHeight = 0;
    106                 int intTextHeight = 0;
    107                 using (var g = txt.CreateGraphics())
    108                 {
    109                     intTxtMaxHeight = (int)g.MeasureString(txt.Text, txt.Font).Height;
    110                     intTextHeight = (int)g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font).Height;
    111                 }
    112                 barV.Maximum = intTxtMaxHeight;
    113                 barV.Value = (control as TextBox).AutoScrollOffset.Y;
    114             }
    115         }
    116         /// <summary>
    117         /// Resets the v scroll location.
    118         /// </summary>
    119         /// <param name="sender">The sender.</param>
    120         private void ResetVScrollLocation(object sender)
    121         {
    122             Control control = (Control)sender;
    123             bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != 0;
    124             bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != 0;
    125             if (control.Visible)
    126             {
    127                 if (m_lstVCache.ContainsKey(control))
    128                 {
    129                     m_lstVCache[control].Location = new System.Drawing.Point(control.Right - m_lstVCache[control].Width - 1, control.Top + 1);
    130                     if (blnHasHScrollbar)
    131                     {
    132                         m_lstVCache[control].Height = control.Height - m_lstVCache[control].Width - 2;
    133                     }
    134                     else
    135                     {
    136                         m_lstVCache[control].Height = control.Height - 2;
    137                     }
    138                 }
    139             }
    140         }
    141         /// <summary>
    142         /// Handles the VisibleChanged event of the control control.
    143         /// </summary>
    144         /// <param name="sender">The source of the event.</param>
    145         /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    146         void control_VisibleChanged(object sender, EventArgs e)
    147         {
    148             Control control = (Control)sender;
    149             if (!control.Visible)
    150             {
    151                 if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
    152                 {
    153                     m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
    154                     m_lstVCache.Remove(control);
    155                 }
    156             }
    157         }
    158 
    159         private const int HSCROLL = 0x100000;
    160         private const int VSCROLL = 0x200000;
    161         private const int STYLE = -16;
    162 
    163         private Dictionary<Control, UCVScrollbar> m_lstVCache = new Dictionary<Control, UCVScrollbar>();
    164         //private Dictionary<ScrollableControl, UCVScrollbar> m_lstHCache = new Dictionary<ScrollableControl, UCVScrollbar>();
    165 
    166         void barV_Scroll(object sender, EventArgs e)
    167         {
    168             UCVScrollbar bar = (UCVScrollbar)sender;
    169             if (m_lstVCache.ContainsValue(bar))
    170             {
    171                 Control c = m_lstVCache.FirstOrDefault(p => p.Value == bar).Key;
    172                 if (c is ScrollableControl)
    173                 {
    174                     (c as ScrollableControl).AutoScrollPosition = new Point(0, bar.Value);
    175                 }
    176                 else if (c is TreeView)
    177                 {
    178                     TreeView tv = (c as TreeView);
    179                     SetTreeViewScrollLocation(tv, tv.Nodes, bar.Value);
    180                 }
    181                 else if (c is TextBox)
    182                 {
    183                     TextBox txt = (c as TextBox);
    184                     SetTextBoxScrollLocation(txt, bar.Value);
    185                 }
    186             }
    187         }
    188 
    189         #region Treeview处理    English:Treeviewu5904u7406
    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("
    ", 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:Treeviewu5904u7406
    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("
    ", txt.Lines.Take(i + 1));
    367                     var size = g.MeasureString(str, txt.Font);
    368                     if (size.Height >= intY)
    369                     {
    370                         txt.SelectionStart = str.Length;
    371                         txt.ScrollToCaret();
    372                         return;
    373                     }
    374                 }
    375             }
    376         }
    377 
    378         void txt_KeyDown(object sender, KeyEventArgs e)
    379         {
    380             if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
    381             {
    382                 TextBox txt = (TextBox)sender;
    383                 if (m_lstVCache.ContainsKey(txt))
    384                 {
    385                     using (var g = txt.CreateGraphics())
    386                     {
    387                         var size = g.MeasureString(txt.Text.Substring(0, txt.SelectionStart), txt.Font);
    388                         m_lstVCache[txt].Value = (int)size.Height;
    389                     }
    390                 }
    391             }
    392         }
    393 
    394         void txt_MouseWheel(object sender, MouseEventArgs e)
    395         {
    396             TextBox txt = (TextBox)sender;
    397             if (m_lstVCache.ContainsKey(txt))
    398             {
    399                 using (var g = txt.CreateGraphics())
    400                 {
    401                     StringBuilder str = new StringBuilder();
    402                     for (int i = 0; i < System.Windows.Forms.SystemInformation.MouseWheelScrollLines; i++)
    403                     {
    404                         str.AppendLine("A");
    405                     }
    406                     var height = (int)g.MeasureString(str.ToString(), txt.Font).Height;
    407                     if (e.Delta < 0)
    408                     {
    409                         if (height + m_lstVCache[txt].Value > m_lstVCache[txt].Maximum)
    410                             m_lstVCache[txt].Value = m_lstVCache[txt].Maximum;
    411                         else
    412                             m_lstVCache[txt].Value += height;
    413                     }
    414                     else
    415                     {
    416                         if (m_lstVCache[txt].Value - height < 0)
    417                             m_lstVCache[txt].Value = 0;
    418                         else
    419                             m_lstVCache[txt].Value -= height;
    420                     }
    421                 }
    422             }
    423         }
    424         #endregion
    425     }
    426 }
    View Code

    代码就这些了

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

    最后的话

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

  • 相关阅读:
    冒泡排序
    CFURLCreateStringByAddingPercentEscapes
    AESCrypt加密与解密
    关于Xcode 的SDK与系统版本理解
    nginx 安全稳定版本
    bcom 遇到的那些问题
    nginx 配置404错误页面
    AES 对称加密解密
    SpringCloud stream连接RabbitMQ收发信息
    springboot1.5 和 2.0 引入 redis 并封装工具类
  • 原文地址:https://www.cnblogs.com/bfyx/p/11550897.html
Copyright © 2020-2023  润新知