C# Textbox,必须同时设置属性Multiline = True、ScrollBars=Horizontal、WordWrap=False才会显示出水平滚动条,且默认字体大小下,控件的Size.Height >= 33才能正常显示完全文本。这非常的丑陋!占空间!
想着能调节压缩一下滚动条的高度就好了,只是现实太残酷,滚动条没有高度属性可设置!!!
只能想办法重写Textbox了。折腾两天,各种百度,终于实现自己想要的结果。
1、新建自定义控件,改变继承自TextBox。
public partial class TinyXScrollBarTextBox : TextBox
2、在TinyXScrollBarTextBox的设计模式中,拖放两个panel作为滚动条和滑块。分别命名为:panelXScrollBar、panelXScrollSlider。
3、在InitializeComponent()函数中设置,this.Controls.Add(this.panelXScrollBar);this.panelXScrollBar.Controls.Add(this.panelXScrollSlider);
4、初始化三个关键属性,
public TinyXScrollBarTextBox()
{
InitializeComponent();
base.Multiline = true;
base.WordWrap = false;
base.ScrollBars = ScrollBars.None;
}
并加入如下代码,屏蔽其修改:
///
/// 屏蔽系统的滚动条设置。并显示为水平滚动,实际为 base.ScrollBars = ScrollBars.None;
///
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public new ScrollBars ScrollBars
{
get
{
return ScrollBars.Horizontal;
}
set
{
base.ScrollBars = ScrollBars.None;
}
}
///
/// 屏蔽系统的多行开关,实际为 base.Multiline = true;
///
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public new bool Multiline
{
get
{
return true;
}
set
{
base.Multiline = true;
}
}
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public new bool WordWrap
{
get
{
return false;
}
set
{
base.WordWrap = false;
}
}
5、文本框文本发生变化时,过滤掉转行、回车(\r or \n)。并禁止输入回车键,使现为多行模式下表现得像单行模式。
protected override void OnTextChanged(EventArgs e)
{
ClearRNChar();
var w = panelXScrollBar.Width;
textGdiWidth = TextRenderer.MeasureText(Text, Font).Width;
if (textGdiWidth > w)
{
this.panelXScrollBar.Visible = true;
var ws = panelXScrollBar.Width * 2 - textGdiWidth;
ws = ws < 25 ? 25 : ws; //计算滑块的长度,并设置最小为25个像素。
panelXScrollSlider.Width = ws;
var sliderW = panelXScrollBar.Width - panelXScrollSlider.Width;
int indexWidth = GetTextGdiWidthByIndex(SelectionStart);
SliderLeft = (int)((indexWidth * 1.0) / textGdiWidth * sliderW);
}
else
{
panelXScrollBar.Visible = false;
var start = SelectionStart;
SelectionStart = 0;
ScrollToCaret();
SelectionStart = start;
}
base.OnTextChanged(e);
}
private void TinyXScrollBarTextBox_KeyDown(object sender, KeyEventArgs e)
{
//屏蔽回车键
if ((int)e.KeyCode == 13)
{
e.SuppressKeyPress = true;
}
}
6、滑块的滑动代码,这部分来源于网络,找不到来源了,也不难。
private static bool IsMove = false; //标识 鼠标在滑块上的运动状态 初始为false
private int X; //定义一个变量 用于记录鼠标进入滑块中并按下时的位置
private void panelXScrollSlider_MouseDown(object sender, MouseEventArgs e) //鼠标对滑块的按下事件
{
IsMove = true; //标识鼠标开始移动
X = e.Location.X; //鼠标的初始位置的X坐标
panelXScrollSlider.BackColor = Color.FromArgb(200, 100, 100, 100); ; //滑块颜色变为深一点的色
}
private void panelXScrollSlider_MouseMove(object sender, MouseEventArgs e) //鼠标对滑块的 移动 事件
{
if (IsMove == true) //如果鼠标开始移动
{
if (panelXScrollSlider.Right >= this.Width)
{
if ((e.Location.X - X) < 0) //如果 鼠标向左滑动
{
panelXScrollSlider.Left += e.Location.X - X; //将滑块的位置增加 增加的量是鼠标移动的距离
}
else //如果鼠标向下移动
{
panelXScrollSlider.Left = this.Width - panelXScrollSlider.Width; //滑块的位置始终为 滑条最底部的位置
}
}
else if (panelXScrollSlider.Left <= 0)
{
if ((e.Location.X - X) > 0)
{
panelXScrollSlider.Left += e.Location.X - X;
}
else
{
panelXScrollSlider.Left = 0;
}
}
else
{
panelXScrollSlider.Left += e.Location.X - X;
}
}
}
private void panelXScrollSlider_MouseUp(object sender, MouseEventArgs e) //当鼠标松开时候 意味着 用户 不再需要滑动滑块
{
IsMove = false; //此时将标识变为false
panelXScrollSlider.BackColor = Color.FromArgb(100, 100, 100, 100); //颜色变为原来的暗色
SliderLeft = panelXScrollSlider.Left;//通过设置触发内容的滚动。
}
private void panelXScrollSlider_MouseEnter(object sender, EventArgs e)
{
panelXScrollSlider.BackColor = Color.FromArgb(200, 100, 100, 100);
}
private void panelXScrollSlider_MouseLeave(object sender, EventArgs e)
{
panelXScrollSlider.BackColor = Color.FromArgb(100, 100, 100, 100);
}
7、鼠标点滚动条的操作:在滑块的右侧点击,则向右滚动,反之亦然
///
/// 在滑块的右侧点击,则向右滚动,反之亦然
///
///
///
private void panelXScrollBar_MouseClick(object sender, MouseEventArgs e)
{
if (Text.Length == 0)
{
return;
}
int oldStart = SelectionStart;
int oldSlectedLen = SelectionLength;
var ns = 0;
if (e.X > panelXScrollSlider.Right)
{
var rightindex = GetCharIndexFromPosition(new Point(this.panelXScrollBar.Right - 3, 1));
ns = rightindex + 1;
ns = ns > Text.Length - 1 ? Text.Length : ns;
}
else if (e.X < panelXScrollSlider.Left)
{
var leftindex = GetCharIndexFromPosition(new Point(3, 1));
ns = leftindex - 1;
ns = ns < 0 ? 0 : ns;
}
SelectionStart = ns;
SelectionLength = 0;
ScrollToCaret();
var left = (int)((ns * 1.0 / Text.Length) * (panelXScrollBar.Width - panelXScrollSlider.Width));
panelXScrollSlider.Left = left;
SelectionStart = oldStart;
SelectionLength = oldSlectedLen;
}
8、滑块与光标的联动。这一块实现得不是丝滑,不过差不多就得了。
找了很久也没有找到文字滚动的控制方式 ,只能利用了ScrollToCaret()来控制。
ScrollToCaret()只要光标能显示出来,就不再滚动,控制起来有些不够丝滑!同时滑块的位置计算也不是很精准,只是大概这样子。
----end----夜已深。不详写了,有兴趣的同学可以下载资源:
C#重写Winform的Textbox单行模式下滚动条。-C#文档类资源-CSDN下载