官网

http://www.hzhcontrols.com

前提

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

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

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

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

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

idkey=6e08741ef16fe53bf0314c1c9e336c4f626047943a8b76bac062361bab6b4f8d">

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

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

一些属性

  /// <summary>
/// The mo large change
/// </summary>
protected int moLargeChange = ;
/// <summary>
/// The mo small change
/// </summary>
protected int moSmallChange = ;
/// <summary>
/// The mo minimum
/// </summary>
protected int moMinimum = ;
/// <summary>
/// The mo maximum
/// </summary>
protected int moMaximum = ;
/// <summary>
/// The mo value
/// </summary>
protected int moValue = ;
/// <summary>
/// The n click point
/// </summary>
private int nClickPoint;
/// <summary>
/// The mo thumb top
/// </summary>
protected int moThumbTop = ;
/// <summary>
/// The mo automatic size
/// </summary>
protected bool moAutoSize = false;
/// <summary>
/// The mo thumb down
/// </summary>
private bool moThumbDown = false;
/// <summary>
/// The mo thumb dragging
/// </summary>
private bool moThumbDragging = false;
/// <summary>
/// Occurs when [scroll].
/// </summary>
public new event EventHandler Scroll = null;
/// <summary>
/// Occurs when [value changed].
/// </summary>
public event EventHandler ValueChanged = null; /// <summary>
/// The BTN height
/// </summary>
private int btnHeight = ;
/// <summary>
/// The m int thumb minimum height
/// </summary>
private int m_intThumbMinHeight = ; /// <summary>
/// Gets or sets the height of the BTN.
/// </summary>
/// <value>The height of the BTN.</value>
public int BtnHeight
{
get { return btnHeight; }
set { btnHeight = value; }
}
/// <summary>
/// Gets or sets the large change.
/// </summary>
/// <value>The large change.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("LargeChange")]
public int LargeChange
{
get { return moLargeChange; }
set
{
moLargeChange = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the small change.
/// </summary>
/// <value>The small change.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("SmallChange")]
public int SmallChange
{
get { return moSmallChange; }
set
{
moSmallChange = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the minimum.
/// </summary>
/// <value>The minimum.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Minimum")]
public int Minimum
{
get { return moMinimum; }
set
{
moMinimum = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the maximum.
/// </summary>
/// <value>The maximum.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Maximum")]
public int Maximum
{
get { return moMaximum; }
set
{
moMaximum = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the value.
/// </summary>
/// <value>The value.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Value")]
public int Value
{
get { return moValue; }
set
{
moValue = value; int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
} //figure out value
int nPixelRange = nTrackHeight - nThumbHeight;
int nRealRange = (Maximum - Minimum) - LargeChange;
float fPerc = 0.0f;
if (nRealRange != )
{
fPerc = (float)moValue / (float)nRealRange; } float fTop = fPerc * nPixelRange;
moThumbTop = (int)fTop; Invalidate();
}
} /// <summary>
/// Gets or sets a value indicating whether [automatic size].
/// </summary>
/// <value><c>true</c> if [automatic size]; otherwise, <c>false</c>.</value>
public override bool AutoSize
{
get
{
return base.AutoSize;
}
set
{
base.AutoSize = value;
if (base.AutoSize)
{
this.Width = ;
}
}
} /// <summary>
/// The thumb color
/// </summary>
private Color thumbColor = Color.FromArgb(, , ); /// <summary>
/// Gets or sets the color of the thumb.
/// </summary>
/// <value>The color of the thumb.</value>
public Color ThumbColor
{
get { return thumbColor; }
set { thumbColor = value; }
}

重绘

  protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SetGDIHigh(); //draw thumb
int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
}
int nTop = moThumbTop;
nTop += btnHeight;
e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(, nTop, this.Width - , nThumbHeight).CreateRoundedRectanglePath(this.ConerRadius)); ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / , btnHeight - Math.Min(, this.Width / )), Math.Min(, this.Width / ), GraphDirection.Upward);
ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / , this.Height - (btnHeight - Math.Min(, this.Width / ))), Math.Min(, this.Width / ), GraphDirection.Downward); }

处理下鼠标事件

  /// <summary>
/// Handles the MouseDown event of the CustomScrollbar control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e)
{
Point ptPoint = this.PointToClient(Cursor.Position);
int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
} int nTop = moThumbTop;
nTop += btnHeight; Rectangle thumbrect = new Rectangle(new Point(, nTop), new Size(this.Width - , nThumbHeight));
if (thumbrect.Contains(ptPoint))
{ //hit the thumb
nClickPoint = (ptPoint.Y - nTop);
//MessageBox.Show(Convert.ToString((ptPoint.Y - nTop)));
this.moThumbDown = true;
} Rectangle uparrowrect = new Rectangle(new Point(, ), new Size(this.Width, btnHeight));
if (uparrowrect.Contains(ptPoint))
{ int nRealRange = (Maximum - Minimum) - LargeChange;
int nPixelRange = (nTrackHeight - nThumbHeight);
if (nRealRange > )
{
if (nPixelRange > )
{
if ((moThumbTop - SmallChange) < )
moThumbTop = ;
else
moThumbTop -= SmallChange; //figure out value
float fPerc = (float)moThumbTop / (float)nPixelRange;
float fValue = fPerc * (Maximum - LargeChange); moValue = (int)fValue; if (ValueChanged != null)
ValueChanged(this, new EventArgs()); if (Scroll != null)
Scroll(this, new EventArgs()); Invalidate();
}
}
} Rectangle downarrowrect = new Rectangle(new Point(, btnHeight + nTrackHeight), new Size(this.Width, btnHeight));
if (downarrowrect.Contains(ptPoint))
{
int nRealRange = (Maximum - Minimum) - LargeChange;
int nPixelRange = (nTrackHeight - nThumbHeight);
if (nRealRange > )
{
if (nPixelRange > )
{
if ((moThumbTop + SmallChange) > nPixelRange)
moThumbTop = nPixelRange;
else
moThumbTop += SmallChange; //figure out value
float fPerc = (float)moThumbTop / (float)nPixelRange;
float fValue = fPerc * (Maximum - LargeChange); moValue = (int)fValue; if (ValueChanged != null)
ValueChanged(this, new EventArgs()); if (Scroll != null)
Scroll(this, new EventArgs()); Invalidate();
}
}
}
} /// <summary>
/// Handles the MouseUp event of the CustomScrollbar control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e)
{
this.moThumbDown = false;
this.moThumbDragging = false;
} /// <summary>
/// Moves the thumb.
/// </summary>
/// <param name="y">The y.</param>
private void MoveThumb(int y)
{
int nRealRange = Maximum - Minimum;
int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
} int nSpot = nClickPoint; int nPixelRange = (nTrackHeight - nThumbHeight);
if (moThumbDown && nRealRange > )
{
if (nPixelRange > )
{
int nNewThumbTop = y - (btnHeight + nSpot); if (nNewThumbTop < )
{
moThumbTop = nNewThumbTop = ;
}
else if (nNewThumbTop > nPixelRange)
{
moThumbTop = nNewThumbTop = nPixelRange;
}
else
{
moThumbTop = y - (btnHeight + nSpot);
} float fPerc = (float)moThumbTop / (float)nPixelRange;
float fValue = fPerc * (Maximum - LargeChange);
moValue = (int)fValue; Application.DoEvents(); Invalidate();
}
}
} /// <summary>
/// Handles the MouseMove event of the CustomScrollbar control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e)
{
if (!moThumbDown)
return; if (moThumbDown == true)
{
this.moThumbDragging = true;
} if (this.moThumbDragging)
{
MoveThumb(e.Y);
} if (ValueChanged != null)
ValueChanged(this, new EventArgs()); if (Scroll != null)
Scroll(this, new EventArgs());
}

完整代码

 // ***********************************************************************
// Assembly : HZH_Controls
// Created : 2019-09-19
//
// ***********************************************************************
// <copyright file="UCVScrollbar.cs">
// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
// </copyright>
//
// Blog: https://www.cnblogs.com/bfyx
// GitHub:https://github.com/kwwwvagaa/NetWinformControl
// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
//
// If you use this code, please keep this note.
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Diagnostics; namespace HZH_Controls.Controls
{ /// <summary>
/// Class UCVScrollbar.
/// Implements the <see cref="HZH_Controls.Controls.UCControlBase" />
/// </summary>
/// <seealso cref="HZH_Controls.Controls.UCControlBase" />
[Designer(typeof(ScrollbarControlDesigner))]
[DefaultEvent("Scroll")]
public class UCVScrollbar : UCControlBase
{
/// <summary>
/// The mo large change
/// </summary>
protected int moLargeChange = ;
/// <summary>
/// The mo small change
/// </summary>
protected int moSmallChange = ;
/// <summary>
/// The mo minimum
/// </summary>
protected int moMinimum = ;
/// <summary>
/// The mo maximum
/// </summary>
protected int moMaximum = ;
/// <summary>
/// The mo value
/// </summary>
protected int moValue = ;
/// <summary>
/// The n click point
/// </summary>
private int nClickPoint;
/// <summary>
/// The mo thumb top
/// </summary>
protected int moThumbTop = ;
/// <summary>
/// The mo automatic size
/// </summary>
protected bool moAutoSize = false;
/// <summary>
/// The mo thumb down
/// </summary>
private bool moThumbDown = false;
/// <summary>
/// The mo thumb dragging
/// </summary>
private bool moThumbDragging = false;
/// <summary>
/// Occurs when [scroll].
/// </summary>
public new event EventHandler Scroll = null;
/// <summary>
/// Occurs when [value changed].
/// </summary>
public event EventHandler ValueChanged = null; /// <summary>
/// The BTN height
/// </summary>
private int btnHeight = ;
/// <summary>
/// The m int thumb minimum height
/// </summary>
private int m_intThumbMinHeight = ; /// <summary>
/// Gets or sets the height of the BTN.
/// </summary>
/// <value>The height of the BTN.</value>
public int BtnHeight
{
get { return btnHeight; }
set { btnHeight = value; }
}
/// <summary>
/// Gets or sets the large change.
/// </summary>
/// <value>The large change.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("LargeChange")]
public int LargeChange
{
get { return moLargeChange; }
set
{
moLargeChange = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the small change.
/// </summary>
/// <value>The small change.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("SmallChange")]
public int SmallChange
{
get { return moSmallChange; }
set
{
moSmallChange = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the minimum.
/// </summary>
/// <value>The minimum.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Minimum")]
public int Minimum
{
get { return moMinimum; }
set
{
moMinimum = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the maximum.
/// </summary>
/// <value>The maximum.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Maximum")]
public int Maximum
{
get { return moMaximum; }
set
{
moMaximum = value;
Invalidate();
}
} /// <summary>
/// Gets or sets the value.
/// </summary>
/// <value>The value.</value>
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("自定义"), Description("Value")]
public int Value
{
get { return moValue; }
set
{
moValue = value; int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
} //figure out value
int nPixelRange = nTrackHeight - nThumbHeight;
int nRealRange = (Maximum - Minimum) - LargeChange;
float fPerc = 0.0f;
if (nRealRange != )
{
fPerc = (float)moValue / (float)nRealRange; } float fTop = fPerc * nPixelRange;
moThumbTop = (int)fTop; Invalidate();
}
} /// <summary>
/// Gets or sets a value indicating whether [automatic size].
/// </summary>
/// <value><c>true</c> if [automatic size]; otherwise, <c>false</c>.</value>
public override bool AutoSize
{
get
{
return base.AutoSize;
}
set
{
base.AutoSize = value;
if (base.AutoSize)
{
this.Width = ;
}
}
} /// <summary>
/// The thumb color
/// </summary>
private Color thumbColor = Color.FromArgb(, , ); /// <summary>
/// Gets or sets the color of the thumb.
/// </summary>
/// <value>The color of the thumb.</value>
public Color ThumbColor
{
get { return thumbColor; }
set { thumbColor = value; }
} /// <summary>
/// Initializes a new instance of the <see cref="UCVScrollbar"/> class.
/// </summary>
public UCVScrollbar()
{
InitializeComponent();
ConerRadius = ;
FillColor = Color.FromArgb(, , );
IsShowRect = false;
IsRadius = true;
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.Selectable, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.UserPaint, true);
} /// <summary>
/// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 事件。
/// </summary>
/// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" />。</param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SetGDIHigh(); //draw thumb
int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
}
int nTop = moThumbTop;
nTop += btnHeight;
e.Graphics.FillPath(new SolidBrush(thumbColor), new Rectangle(, nTop, this.Width - , nThumbHeight).CreateRoundedRectanglePath(this.ConerRadius)); ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / , btnHeight - Math.Min(, this.Width / )), Math.Min(, this.Width / ), GraphDirection.Upward);
ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(thumbColor), new Point(this.Width / , this.Height - (btnHeight - Math.Min(, this.Width / ))), Math.Min(, this.Width / ), GraphDirection.Downward); } /// <summary>
/// Initializes the component.
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// UCVScrollbar
//
this.MinimumSize = new System.Drawing.Size(, );
this.Name = "UCVScrollbar";
this.Size = new System.Drawing.Size(, );
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseDown);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.CustomScrollbar_MouseUp);
this.ResumeLayout(false); } /// <summary>
/// Handles the MouseDown event of the CustomScrollbar control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e)
{
Point ptPoint = this.PointToClient(Cursor.Position);
int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
} int nTop = moThumbTop;
nTop += btnHeight; Rectangle thumbrect = new Rectangle(new Point(, nTop), new Size(this.Width - , nThumbHeight));
if (thumbrect.Contains(ptPoint))
{ //hit the thumb
nClickPoint = (ptPoint.Y - nTop);
//MessageBox.Show(Convert.ToString((ptPoint.Y - nTop)));
this.moThumbDown = true;
} Rectangle uparrowrect = new Rectangle(new Point(, ), new Size(this.Width, btnHeight));
if (uparrowrect.Contains(ptPoint))
{ int nRealRange = (Maximum - Minimum) - LargeChange;
int nPixelRange = (nTrackHeight - nThumbHeight);
if (nRealRange > )
{
if (nPixelRange > )
{
if ((moThumbTop - SmallChange) < )
moThumbTop = ;
else
moThumbTop -= SmallChange; //figure out value
float fPerc = (float)moThumbTop / (float)nPixelRange;
float fValue = fPerc * (Maximum - LargeChange); moValue = (int)fValue; if (ValueChanged != null)
ValueChanged(this, new EventArgs()); if (Scroll != null)
Scroll(this, new EventArgs()); Invalidate();
}
}
} Rectangle downarrowrect = new Rectangle(new Point(, btnHeight + nTrackHeight), new Size(this.Width, btnHeight));
if (downarrowrect.Contains(ptPoint))
{
int nRealRange = (Maximum - Minimum) - LargeChange;
int nPixelRange = (nTrackHeight - nThumbHeight);
if (nRealRange > )
{
if (nPixelRange > )
{
if ((moThumbTop + SmallChange) > nPixelRange)
moThumbTop = nPixelRange;
else
moThumbTop += SmallChange; //figure out value
float fPerc = (float)moThumbTop / (float)nPixelRange;
float fValue = fPerc * (Maximum - LargeChange); moValue = (int)fValue; if (ValueChanged != null)
ValueChanged(this, new EventArgs()); if (Scroll != null)
Scroll(this, new EventArgs()); Invalidate();
}
}
}
} /// <summary>
/// Handles the MouseUp event of the CustomScrollbar control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e)
{
this.moThumbDown = false;
this.moThumbDragging = false;
} /// <summary>
/// Moves the thumb.
/// </summary>
/// <param name="y">The y.</param>
private void MoveThumb(int y)
{
int nRealRange = Maximum - Minimum;
int nTrackHeight = (this.Height - btnHeight * );
float fThumbHeight = ((float)LargeChange / (float)Maximum) * nTrackHeight;
int nThumbHeight = (int)fThumbHeight; if (nThumbHeight > nTrackHeight)
{
nThumbHeight = nTrackHeight;
fThumbHeight = nTrackHeight;
}
if (nThumbHeight < m_intThumbMinHeight)
{
nThumbHeight = m_intThumbMinHeight;
fThumbHeight = m_intThumbMinHeight;
} int nSpot = nClickPoint; int nPixelRange = (nTrackHeight - nThumbHeight);
if (moThumbDown && nRealRange > )
{
if (nPixelRange > )
{
int nNewThumbTop = y - (btnHeight + nSpot); if (nNewThumbTop < )
{
moThumbTop = nNewThumbTop = ;
}
else if (nNewThumbTop > nPixelRange)
{
moThumbTop = nNewThumbTop = nPixelRange;
}
else
{
moThumbTop = y - (btnHeight + nSpot);
} float fPerc = (float)moThumbTop / (float)nPixelRange;
float fValue = fPerc * (Maximum - LargeChange);
moValue = (int)fValue; Application.DoEvents(); Invalidate();
}
}
} /// <summary>
/// Handles the MouseMove event of the CustomScrollbar control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e)
{
if (!moThumbDown)
return; if (moThumbDown == true)
{
this.moThumbDragging = true;
} if (this.moThumbDragging)
{
MoveThumb(e.Y);
} if (ValueChanged != null)
ValueChanged(this, new EventArgs()); if (Scroll != null)
Scroll(this, new EventArgs());
} } /// <summary>
/// Class ScrollbarControlDesigner.
/// Implements the <see cref="System.Windows.Forms.Design.ControlDesigner" />
/// </summary>
/// <seealso cref="System.Windows.Forms.Design.ControlDesigner" />
internal class ScrollbarControlDesigner : System.Windows.Forms.Design.ControlDesigner
{
/// <summary>
/// 获取指示组件的移动功能的选择规则。
/// </summary>
/// <value>The selection rules.</value>
public override SelectionRules SelectionRules
{
get
{
SelectionRules selectionRules = base.SelectionRules;
PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(this.Component)["AutoSize"];
if (propDescriptor != null)
{
bool autoSize = (bool)propDescriptor.GetValue(this.Component);
if (autoSize)
{
selectionRules = SelectionRules.Visible | SelectionRules.Moveable | SelectionRules.BottomSizeable | SelectionRules.TopSizeable;
}
else
{
selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable;
}
}
return selectionRules;
}
}
}
}

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

新增类ScrollbarComponent,继承 Component, IExtenderProvider

实现接口方法

  public bool CanExtend(object extendee)
{
if (extendee is ScrollableControl)
{
ScrollableControl control = (ScrollableControl)extendee;
if (control.AutoScroll == true)
{
return true;
}
}
else if (extendee is TreeView)
{
TreeView control = (TreeView)extendee;
if (control.Scrollable)
{
return true;
}
}
else if (extendee is TextBox)
{
TextBox control = (TextBox)extendee;
if (control.Multiline && control.ScrollBars != ScrollBars.None)
{
return true;
}
}
return false;
}

扩展控件属性

   [Browsable(true), Category("自定义属性"), Description("是否使用自定义滚动条"), DisplayName("UserCustomScrollbar"), Localizable(true)]
public bool GetUserCustomScrollbar(Control control)
{
return m_blnUserCustomScrollbar;
} public void SetUserCustomScrollbar(Control control, bool blnUserCustomScrollbar)
{
m_blnUserCustomScrollbar = blnUserCustomScrollbar;
control.VisibleChanged += control_VisibleChanged;
control.SizeChanged += control_SizeChanged;
control.LocationChanged += control_LocationChanged;
control.Disposed += control_Disposed; if (control is TreeView)
{
TreeView tv = (TreeView)control;
tv.MouseWheel += tv_MouseWheel;
tv.AfterSelect += tv_AfterSelect;
tv.AfterExpand += tv_AfterExpand;
tv.AfterCollapse += tv_AfterCollapse;
}
else if (control is TextBox)
{
TextBox txt = (TextBox)control;
txt.MouseWheel += txt_MouseWheel;
txt.TextChanged += txt_TextChanged; txt.KeyDown += txt_KeyDown;
}
control_SizeChanged(control, null);
}

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

  void control_Disposed(object sender, EventArgs e)
{
Control control = (Control)sender;
if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
{
m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
m_lstVCache.Remove(control);
}
} void control_LocationChanged(object sender, EventArgs e)
{
ResetVScrollLocation(sender);
} void control_SizeChanged(object sender, EventArgs e)
{
if (ControlHelper.IsDesignMode())
{
return;
}
else
{
var control = sender as Control; bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != ;
bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != ;
if (blnHasVScrollbar)
{
if (!m_lstVCache.ContainsKey(control))
{
if (control.Parent != null)
{
UCVScrollbar barV = new UCVScrollbar();
barV.Scroll += barV_Scroll;
m_lstVCache[control] = barV;
if (blnHasHScrollbar)
{
barV.Height = control.Height - barV.Width - ;
}
else
{
barV.Height = control.Height - ;
}
SetVMaxNum(control);
barV.Location = new System.Drawing.Point(control.Right - barV.Width - , control.Top + );
control.Parent.Controls.Add(barV);
int intControlIndex = control.Parent.Controls.GetChildIndex(control);
control.Parent.Controls.SetChildIndex(barV, intControlIndex);
}
}
else
{
SetVMaxNum(control);
}
}
else
{
if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
{
m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
m_lstVCache.Remove(control);
}
} //if (blnHasHScrollbar)
//{
// if (control.Parent != null)
// { // }
//}
//else
//{
// if (m_lstHCache.ContainsKey(control))
// {
// if (m_lstHCache[control].Visible)
// {
// m_lstHCache[control].Parent.Controls.Remove(m_lstHCache[control]);
// }
// }
//}
}
ResetVScrollLocation(sender);
} private void SetVMaxNum(Control control)
{
if (!m_lstVCache.ContainsKey(control))
return;
UCVScrollbar barV = m_lstVCache[control];
if (control is ScrollableControl)
{
barV.Maximum = (control as ScrollableControl).VerticalScroll.Maximum;
barV.Value = (control as ScrollableControl).VerticalScroll.Value;
}
else if (control is TreeView)
{
barV.Maximum = GetTreeNodeMaxY(control as TreeView);
barV.Value = (control as TreeView).AutoScrollOffset.Y;
}
else if (control is TextBox)
{
TextBox txt = (TextBox)control;
int intTxtMaxHeight = ;
int intTextHeight = ;
using (var g = txt.CreateGraphics())
{
intTxtMaxHeight = (int)g.MeasureString(txt.Text, txt.Font).Height;
intTextHeight = (int)g.MeasureString(txt.Text.Substring(, txt.SelectionStart), txt.Font).Height;
}
barV.Maximum = intTxtMaxHeight;
barV.Value = (control as TextBox).AutoScrollOffset.Y;
}
}
/// <summary>
/// Resets the v scroll location.
/// </summary>
/// <param name="sender">The sender.</param>
private void ResetVScrollLocation(object sender)
{
Control control = (Control)sender;
bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != ;
bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != ;
if (control.Visible)
{
if (m_lstVCache.ContainsKey(control))
{
m_lstVCache[control].Location = new System.Drawing.Point(control.Right - m_lstVCache[control].Width - , control.Top + );
if (blnHasHScrollbar)
{
m_lstVCache[control].Height = control.Height - m_lstVCache[control].Width - ;
}
else
{
m_lstVCache[control].Height = control.Height - ;
}
}
}
}
/// <summary>
/// Handles the VisibleChanged event of the control control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void control_VisibleChanged(object sender, EventArgs e)
{
Control control = (Control)sender;
if (!control.Visible)
{
if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
{
m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
m_lstVCache.Remove(control);
}
}
} private const int HSCROLL = 0x100000;
private const int VSCROLL = 0x200000;
private const int STYLE = -; private Dictionary<Control, UCVScrollbar> m_lstVCache = new Dictionary<Control, UCVScrollbar>();
//private Dictionary<ScrollableControl, UCVScrollbar> m_lstHCache = new Dictionary<ScrollableControl, UCVScrollbar>(); void barV_Scroll(object sender, EventArgs e)
{
UCVScrollbar bar = (UCVScrollbar)sender;
if (m_lstVCache.ContainsValue(bar))
{
Control c = m_lstVCache.FirstOrDefault(p => p.Value == bar).Key;
if (c is ScrollableControl)
{
(c as ScrollableControl).AutoScrollPosition = new Point(, bar.Value);
}
else if (c is TreeView)
{
TreeView tv = (c as TreeView);
SetTreeViewScrollLocation(tv, tv.Nodes, bar.Value);
}
else if (c is TextBox)
{
TextBox txt = (c as TextBox);
SetTextBoxScrollLocation(txt, bar.Value);
}
}
} #region Treeview处理 English:Treeview\u5904\u7406
void tv_AfterCollapse(object sender, TreeViewEventArgs e)
{
control_SizeChanged(sender as Control, null);
} void tv_AfterExpand(object sender, TreeViewEventArgs e)
{
control_SizeChanged(sender as Control, null);
}
/// <summary>
/// Gets the tree node 最大高度
/// </summary>
/// <param name="tv">The tv.</param>
/// <returns>System.Int32.</returns>
private int GetTreeNodeMaxY(TreeView tv)
{
TreeNode tnLast = tv.Nodes[tv.Nodes.Count - ];
begin:
if (tnLast.IsExpanded && tnLast.Nodes.Count > )
{
tnLast = tnLast.LastNode;
goto begin;
}
return tnLast.Bounds.Bottom;
}
void tv_AfterSelect(object sender, TreeViewEventArgs e)
{
TreeView tv = (TreeView)sender;
if (m_lstVCache.ContainsKey(tv))
{
m_lstVCache[tv].Value = tv.Nodes.Count > ? Math.Abs(tv.Nodes[].Bounds.Top) : ;
}
} void tv_MouseWheel(object sender, MouseEventArgs e)
{
TreeView tv = (TreeView)sender;
if (m_lstVCache.ContainsKey(tv))
{
m_lstVCache[tv].Value = tv.Nodes.Count > ? Math.Abs(tv.Nodes[].Bounds.Top) : ;
}
}
/// <summary>
/// Sets the TreeView scroll location.
/// </summary>
/// <param name="tv">The tv.</param>
/// <param name="tns">The TNS.</param>
/// <param name="intY">The int y.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool SetTreeViewScrollLocation(TreeView tv, TreeNodeCollection tns, int intY)
{
for (int i = ; i < tns.Count; i++)
{
if (intY >= tns[i].Bounds.Top - tv.Nodes[].Bounds.Top - && intY <= tns[i].Bounds.Bottom - tv.Nodes[].Bounds.Top + )
{
tns[i].EnsureVisible();
return true;
}
else if (tns[i].IsExpanded && tns[i].Nodes.Count > )
{
bool bln = SetTreeViewScrollLocation(tv, tns[i].Nodes, intY);
if (bln)
return true;
}
}
return false;
}
#endregion #region TextBox处理 English:TextBox Processing void txt_TextChanged(object sender, EventArgs e)
{
TextBox txt = sender as TextBox;
control_SizeChanged(txt, null);
SetVMaxNum(txt);
if (m_lstVCache.ContainsKey(txt))
{
using (var g = txt.CreateGraphics())
{
var size = g.MeasureString(txt.Text.Substring(, txt.SelectionStart), txt.Font);
m_lstVCache[txt].Value = (int)size.Height;
}
}
}
private void SetTextBoxScrollLocation(TextBox txt, int intY)
{
using (var g = txt.CreateGraphics())
{
for (int i = ; i < txt.Lines.Length; i++)
{
string str = string.Join("\n", txt.Lines.Take(i + ));
var size = g.MeasureString(str, txt.Font);
if (size.Height >= intY)
{
txt.SelectionStart = str.Length;
txt.ScrollToCaret();
return;
}
}
}
} void txt_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
{
TextBox txt = (TextBox)sender;
if (m_lstVCache.ContainsKey(txt))
{
using (var g = txt.CreateGraphics())
{
var size = g.MeasureString(txt.Text.Substring(, txt.SelectionStart), txt.Font);
m_lstVCache[txt].Value = (int)size.Height;
}
}
}
} void txt_MouseWheel(object sender, MouseEventArgs e)
{
TextBox txt = (TextBox)sender;
if (m_lstVCache.ContainsKey(txt))
{
using (var g = txt.CreateGraphics())
{
StringBuilder str = new StringBuilder();
for (int i = ; i < System.Windows.Forms.SystemInformation.MouseWheelScrollLines; i++)
{
str.AppendLine("A");
}
var height = (int)g.MeasureString(str.ToString(), txt.Font).Height;
if (e.Delta < )
{
if (height + m_lstVCache[txt].Value > m_lstVCache[txt].Maximum)
m_lstVCache[txt].Value = m_lstVCache[txt].Maximum;
else
m_lstVCache[txt].Value += height;
}
else
{
if (m_lstVCache[txt].Value - height < )
m_lstVCache[txt].Value = ;
else
m_lstVCache[txt].Value -= height;
}
}
}
}
#endregion

完整代码

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace HZH_Controls.Controls.ScrollBar
{
[ProvideProperty("UserCustomScrollbar", typeof(Control))]
public class ScrollbarComponent : Component, IExtenderProvider
{
public ScrollbarComponent()
{
} public ScrollbarComponent(IContainer container)
{
container.Add(this);
}
bool m_blnUserCustomScrollbar = true;
public bool CanExtend(object extendee)
{
if (extendee is ScrollableControl)
{
ScrollableControl control = (ScrollableControl)extendee;
if (control.AutoScroll == true)
{
return true;
}
}
else if (extendee is TreeView)
{
TreeView control = (TreeView)extendee;
if (control.Scrollable)
{
return true;
}
}
else if (extendee is TextBox)
{
TextBox control = (TextBox)extendee;
if (control.Multiline && control.ScrollBars != ScrollBars.None)
{
return true;
}
}
return false;
} [Browsable(true), Category("自定义属性"), Description("是否使用自定义滚动条"), DisplayName("UserCustomScrollbar"), Localizable(true)]
public bool GetUserCustomScrollbar(Control control)
{
return m_blnUserCustomScrollbar;
} public void SetUserCustomScrollbar(Control control, bool blnUserCustomScrollbar)
{
m_blnUserCustomScrollbar = blnUserCustomScrollbar;
control.VisibleChanged += control_VisibleChanged;
control.SizeChanged += control_SizeChanged;
control.LocationChanged += control_LocationChanged;
control.Disposed += control_Disposed; if (control is TreeView)
{
TreeView tv = (TreeView)control;
tv.MouseWheel += tv_MouseWheel;
tv.AfterSelect += tv_AfterSelect;
tv.AfterExpand += tv_AfterExpand;
tv.AfterCollapse += tv_AfterCollapse;
}
else if (control is TextBox)
{
TextBox txt = (TextBox)control;
txt.MouseWheel += txt_MouseWheel;
txt.TextChanged += txt_TextChanged; txt.KeyDown += txt_KeyDown;
}
control_SizeChanged(control, null);
} void control_Disposed(object sender, EventArgs e)
{
Control control = (Control)sender;
if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
{
m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
m_lstVCache.Remove(control);
}
} void control_LocationChanged(object sender, EventArgs e)
{
ResetVScrollLocation(sender);
} void control_SizeChanged(object sender, EventArgs e)
{
if (ControlHelper.IsDesignMode())
{
return;
}
else
{
var control = sender as Control; bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != ;
bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != ;
if (blnHasVScrollbar)
{
if (!m_lstVCache.ContainsKey(control))
{
if (control.Parent != null)
{
UCVScrollbar barV = new UCVScrollbar();
barV.Scroll += barV_Scroll;
m_lstVCache[control] = barV;
if (blnHasHScrollbar)
{
barV.Height = control.Height - barV.Width - ;
}
else
{
barV.Height = control.Height - ;
}
SetVMaxNum(control);
barV.Location = new System.Drawing.Point(control.Right - barV.Width - , control.Top + );
control.Parent.Controls.Add(barV);
int intControlIndex = control.Parent.Controls.GetChildIndex(control);
control.Parent.Controls.SetChildIndex(barV, intControlIndex);
}
}
else
{
SetVMaxNum(control);
}
}
else
{
if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
{
m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
m_lstVCache.Remove(control);
}
} //if (blnHasHScrollbar)
//{
// if (control.Parent != null)
// { // }
//}
//else
//{
// if (m_lstHCache.ContainsKey(control))
// {
// if (m_lstHCache[control].Visible)
// {
// m_lstHCache[control].Parent.Controls.Remove(m_lstHCache[control]);
// }
// }
//}
}
ResetVScrollLocation(sender);
} private void SetVMaxNum(Control control)
{
if (!m_lstVCache.ContainsKey(control))
return;
UCVScrollbar barV = m_lstVCache[control];
if (control is ScrollableControl)
{
barV.Maximum = (control as ScrollableControl).VerticalScroll.Maximum;
barV.Value = (control as ScrollableControl).VerticalScroll.Value;
}
else if (control is TreeView)
{
barV.Maximum = GetTreeNodeMaxY(control as TreeView);
barV.Value = (control as TreeView).AutoScrollOffset.Y;
}
else if (control is TextBox)
{
TextBox txt = (TextBox)control;
int intTxtMaxHeight = ;
int intTextHeight = ;
using (var g = txt.CreateGraphics())
{
intTxtMaxHeight = (int)g.MeasureString(txt.Text, txt.Font).Height;
intTextHeight = (int)g.MeasureString(txt.Text.Substring(, txt.SelectionStart), txt.Font).Height;
}
barV.Maximum = intTxtMaxHeight;
barV.Value = (control as TextBox).AutoScrollOffset.Y;
}
}
/// <summary>
/// Resets the v scroll location.
/// </summary>
/// <param name="sender">The sender.</param>
private void ResetVScrollLocation(object sender)
{
Control control = (Control)sender;
bool blnHasVScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & VSCROLL) != ;
bool blnHasHScrollbar = control.IsHandleCreated && (ControlHelper.GetWindowLong(control.Handle, STYLE) & HSCROLL) != ;
if (control.Visible)
{
if (m_lstVCache.ContainsKey(control))
{
m_lstVCache[control].Location = new System.Drawing.Point(control.Right - m_lstVCache[control].Width - , control.Top + );
if (blnHasHScrollbar)
{
m_lstVCache[control].Height = control.Height - m_lstVCache[control].Width - ;
}
else
{
m_lstVCache[control].Height = control.Height - ;
}
}
}
}
/// <summary>
/// Handles the VisibleChanged event of the control control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void control_VisibleChanged(object sender, EventArgs e)
{
Control control = (Control)sender;
if (!control.Visible)
{
if (m_lstVCache.ContainsKey(control) && m_lstVCache[control].Parent != null)
{
m_lstVCache[control].Parent.Controls.Remove(m_lstVCache[control]);
m_lstVCache.Remove(control);
}
}
} private const int HSCROLL = 0x100000;
private const int VSCROLL = 0x200000;
private const int STYLE = -; private Dictionary<Control, UCVScrollbar> m_lstVCache = new Dictionary<Control, UCVScrollbar>();
//private Dictionary<ScrollableControl, UCVScrollbar> m_lstHCache = new Dictionary<ScrollableControl, UCVScrollbar>(); void barV_Scroll(object sender, EventArgs e)
{
UCVScrollbar bar = (UCVScrollbar)sender;
if (m_lstVCache.ContainsValue(bar))
{
Control c = m_lstVCache.FirstOrDefault(p => p.Value == bar).Key;
if (c is ScrollableControl)
{
(c as ScrollableControl).AutoScrollPosition = new Point(, bar.Value);
}
else if (c is TreeView)
{
TreeView tv = (c as TreeView);
SetTreeViewScrollLocation(tv, tv.Nodes, bar.Value);
}
else if (c is TextBox)
{
TextBox txt = (c as TextBox);
SetTextBoxScrollLocation(txt, bar.Value);
}
}
} #region Treeview处理 English:Treeview\u5904\u7406
void tv_AfterCollapse(object sender, TreeViewEventArgs e)
{
control_SizeChanged(sender as Control, null);
} void tv_AfterExpand(object sender, TreeViewEventArgs e)
{
control_SizeChanged(sender as Control, null);
}
/// <summary>
/// Gets the tree node 最大高度
/// </summary>
/// <param name="tv">The tv.</param>
/// <returns>System.Int32.</returns>
private int GetTreeNodeMaxY(TreeView tv)
{
TreeNode tnLast = tv.Nodes[tv.Nodes.Count - ];
begin:
if (tnLast.IsExpanded && tnLast.Nodes.Count > )
{
tnLast = tnLast.LastNode;
goto begin;
}
return tnLast.Bounds.Bottom;
}
void tv_AfterSelect(object sender, TreeViewEventArgs e)
{
TreeView tv = (TreeView)sender;
if (m_lstVCache.ContainsKey(tv))
{
m_lstVCache[tv].Value = tv.Nodes.Count > ? Math.Abs(tv.Nodes[].Bounds.Top) : ;
}
} void tv_MouseWheel(object sender, MouseEventArgs e)
{
TreeView tv = (TreeView)sender;
if (m_lstVCache.ContainsKey(tv))
{
m_lstVCache[tv].Value = tv.Nodes.Count > ? Math.Abs(tv.Nodes[].Bounds.Top) : ;
}
}
/// <summary>
/// Sets the TreeView scroll location.
/// </summary>
/// <param name="tv">The tv.</param>
/// <param name="tns">The TNS.</param>
/// <param name="intY">The int y.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool SetTreeViewScrollLocation(TreeView tv, TreeNodeCollection tns, int intY)
{
for (int i = ; i < tns.Count; i++)
{
if (intY >= tns[i].Bounds.Top - tv.Nodes[].Bounds.Top - && intY <= tns[i].Bounds.Bottom - tv.Nodes[].Bounds.Top + )
{
tns[i].EnsureVisible();
return true;
}
else if (tns[i].IsExpanded && tns[i].Nodes.Count > )
{
bool bln = SetTreeViewScrollLocation(tv, tns[i].Nodes, intY);
if (bln)
return true;
}
}
return false;
}
#endregion #region TextBox处理 English:TextBox Processing void txt_TextChanged(object sender, EventArgs e)
{
TextBox txt = sender as TextBox;
control_SizeChanged(txt, null);
SetVMaxNum(txt);
if (m_lstVCache.ContainsKey(txt))
{
using (var g = txt.CreateGraphics())
{
var size = g.MeasureString(txt.Text.Substring(, txt.SelectionStart), txt.Font);
m_lstVCache[txt].Value = (int)size.Height;
}
}
}
private void SetTextBoxScrollLocation(TextBox txt, int intY)
{
using (var g = txt.CreateGraphics())
{
for (int i = ; i < txt.Lines.Length; i++)
{
string str = string.Join("\n", txt.Lines.Take(i + ));
var size = g.MeasureString(str, txt.Font);
if (size.Height >= intY)
{
txt.SelectionStart = str.Length;
txt.ScrollToCaret();
return;
}
}
}
} void txt_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
{
TextBox txt = (TextBox)sender;
if (m_lstVCache.ContainsKey(txt))
{
using (var g = txt.CreateGraphics())
{
var size = g.MeasureString(txt.Text.Substring(, txt.SelectionStart), txt.Font);
m_lstVCache[txt].Value = (int)size.Height;
}
}
}
} void txt_MouseWheel(object sender, MouseEventArgs e)
{
TextBox txt = (TextBox)sender;
if (m_lstVCache.ContainsKey(txt))
{
using (var g = txt.CreateGraphics())
{
StringBuilder str = new StringBuilder();
for (int i = ; i < System.Windows.Forms.SystemInformation.MouseWheelScrollLines; i++)
{
str.AppendLine("A");
}
var height = (int)g.MeasureString(str.ToString(), txt.Font).Height;
if (e.Delta < )
{
if (height + m_lstVCache[txt].Value > m_lstVCache[txt].Maximum)
m_lstVCache[txt].Value = m_lstVCache[txt].Maximum;
else
m_lstVCache[txt].Value += height;
}
else
{
if (m_lstVCache[txt].Value - height < )
m_lstVCache[txt].Value = ;
else
m_lstVCache[txt].Value -= height;
}
}
}
}
#endregion
}
}

代码就这些了

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

最后的话

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

(六十九)c#Winform自定义控件-垂直滚动条的更多相关文章

  1. (六十)c#Winform自定义控件-鼓风机(工业)

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  2. (八十九)c#Winform自定义控件-自定义滚动条(treeview、panel、datagridview、listbox、listview、textbox)

    官网 http://www.hzhcontrols.com/ 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kw ...

  3. 第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能

    第三百六十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索功能 Django实现搜索功能 1.在Django配置搜索结果页的路由映 ...

  4. “全栈2019”Java第六十九章:内部类访问外部类成员详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. (三十)c#Winform自定义控件-文本框(三)

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  6. (六十七)c#Winform自定义控件-柱状图

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  7. (二十)c#Winform自定义控件-有后退的窗体

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  8. (五十)c#Winform自定义控件-滑块

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  9. OpenCV开发笔记(六十九):红胖子8分钟带你使用传统方法识别已知物体(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

随机推荐

  1. Day3 AntV/G2图表的组成

    简介 为了更好的使用G2进行数据可视化,我们需要先了解G2图表的组成及其相关概念. 完整的G2图表组成如下图所示:可以看出图表主要由axes(坐标轴axis的复数),tooltip(提示信息),gui ...

  2. STL 队列

    头文件 #include <queue> 定义 普通队列: queue < int > q; 优先队列: priority_queue < int, vector< ...

  3. 构建企业级数据湖?Azure Data Lake Storage Gen2不容错过(上)

    背景 相较传统的重量级OLAP数据仓库,“数据湖”以其数据体量大.综合成本低.支持非结构化数据.查询灵活多变等特点,受到越来越多企业的青睐,逐渐成为了现代数据平台的核心和架构范式. 数据湖的核心功能, ...

  4. appiumstudio工具-----实现windows上安卓、IOS自动化测试

    博主用的是win10,用python+appium做完安卓的自动化第一个版本后,大量地搜索windows上做IOS自动化的解决办法,有的建议用虚拟机,安装苹果的系统,没有实践过,据说效果不很好.然后, ...

  5. jenkins增量更新及重启服务步骤

    jenkins增量更新步骤:(以creditsys_service_tomcat为例) 1.SecureCRT 或者Xshell 连接服务器192.168.*.*,账号:test/**** 2.cd ...

  6. RANSAC简史(一)——RANSAC之初

    在开始正式的介绍之前,先做一个简单的定义,以免产生歧义: 1.本文中的“数据点”是指: 1)对于直线拟合.平面拟合等问题,即为相应的二维/三维坐标点: 2)对于从匹配点中估计基本矩阵.单应矩阵等问题, ...

  7. MySQL数据库安装步骤

    目录 MySQL数据库安装 MySQL数据库安装 MySQL Windows下载地址:https://dev.mysql.com/downloads 我们这里选择5.6.45版本下载,下载zip. 点 ...

  8. Java 最全异常讲解

    1. 导引问题 实际工作中,遇到的情况不可能是非常完美的.比如:你写的某个模块,用户输入不一定符合你的要求.你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是 ...

  9. Python爬虫爬取全书网小说,程序源码+程序详细分析

    Python爬虫爬取全书网小说教程 第一步:打开谷歌浏览器,搜索全书网,然后再点击你想下载的小说,进入图一页面后点击F12选择Network,如果没有内容按F5刷新一下 点击Network之后出现如下 ...

  10. VS code 进行 flutter 调试时启动后就停止,无法调试的问题

    在编写flutter时,更新需要按 r 或着 R,这就有点麻烦,当然强大的VS code给我们提供了自动更新的功能,那就是调试功能. 首先需要给VS code安装Flutter与Dart插件. 在VS ...