.Net FCL 中的 System.Windows.Forms.TextBox 是一个常用的控件,然而此控件不支持插入/改写状态的切换功能。本文介绍如何来为 System.Windows.Forms.TextBox 添加此功能。
以下是本控件的全部源代码,您可以加入一个项目中直接编译以生成该控件。
注意:本控件禁止了 Multiline 功能,还有一个小 BUG 没有处理掉。using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Effortech.Library.Controls
{
/// <summary>
/// 能够切换插入/改写状态的文本框控件
/// </summary>
public class OverWritableTextBox : System.Windows.Forms.TextBox
{
#region Class Variables
private bool isOverWrite = false;
#endregion
#region Constructors
public OverWritableTextBox()
{
base.Multiline = false;
}
#endregion
#region Overrides
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
this.ForceSelectOneChar();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp (e);
if (e.Button == MouseButtons.Left)
{
this.ForceSelectOneChar();
}
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged (e);
this.ForceSelectOneChar();
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress (e);
if ((e.KeyChar == (char)8) &&
this.isOverWrite )
{
this.SelectionLength = 0;
}
}
protected override void OnReadOnlyChanged(EventArgs e)
{
base.OnReadOnlyChanged (e);
if (this.ReadOnly)
{
this.isOverWrite = false;
this.SelectionLength = 0;
}
}
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged (e);
if (this.Enabled == false)
{
this.isOverWrite = false;
this.SelectionLength = 0;
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
// 此处重写 OnKeyUp 并调用 ForceSelectOneChar 方法的唯一原因:
// 当组合使用 Shift/Ctrl 和移动键时,可能会使得
// this.SelectionLength 为 0,这在改写状态下是不希望出现的。
//
// BUG ——
// 执行以下方法的负面效果是:如果使用 Shift + 左移键,当取消了所选中的字符时,
// 控件会强制选取一个字符,这就使得左移键看起来失效了。
// 但是此时用户操作只要不放开左移键,仍可继续往左移动光标。
//
// 应采用 Win32 KeyBoard API 来监测 Shift/Ctrl 键的弹出事件,然后再调用以下方法才比较妥当。
// 以后再补吧。
// 如果哪位兄台有什么高见,一定要告诉我哦。
this.ForceSelectOneChar();
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
switch(e.KeyCode)
{
case Keys.Insert:
if (this.ReadOnly == false)
{
if ( this.isOverWrite )
{
this.isOverWrite = false;
}
else
{
this.isOverWrite = true;
this.ForceSelectOneChar();
}
}
break;
case Keys.Left:
case Keys.Up:
if ( this.isOverWrite && // 不对有 Shift 或 Ctrl 键按下时进行任何处理。
(Control.ModifierKeys & Keys.Shift) != Keys.Shift &&
(Control.ModifierKeys & Keys.Control) != Keys.Control )
{
if ( this.SelectionStart > 0)
{
this.SelectionStart--;
this.SelectionLength = 1;
}
e.Handled = true;
}
break;
case Keys.Right:
case Keys.Down:
if ( this.isOverWrite && // 不对有 Shift 或 Ctrl 键按下时进行任何处理。
(Control.ModifierKeys & Keys.Shift) != Keys.Shift &&
(Control.ModifierKeys & Keys.Control) != Keys.Control)
{
if ( this.SelectionStart < this.Text.Length)
{
this.SelectionStart = this.SelectionLength + this.SelectionStart;
this.SelectionLength = 1;
}
e.Handled = true;
}
break;
default:
this.ForceSelectOneChar();
break;
}
}
#endregion
/// <summary>
/// 改写状态下,若没有选取任何字符,强制必须至少选取一个字符。
/// </summary>
private void ForceSelectOneChar()
{
if (this.isOverWrite && this.SelectionLength == 0)
{
this.SelectionLength = 1; // 此操作当已位于最后一个位置时无效,但并不会抛出异常。
}
}
/// <summary>
/// 因为本控件没有处理多行方式下的改写功能,所以暂禁。
/// </summary>
[Browsable(false)]
public new bool Multiline
{
get
{
return base.Multiline;
}
set
{
if (value == true)
throw new NotSupportedException();
base.Multiline = value;
}
}
/// <summary>
/// 获取是否处于改写状态
/// 暂时认为没有必要提供本属性的设置(set)操作
/// </summary>
public bool OverWriting
{
get
{
return this.isOverWrite;
}
}
}
}
最后向 CMIC(大象)致谢。