空模板文本框
本指南展示了如何扩展标准 TextBox 以具有“空值”模板
引言
本指南将向您展示如何创建一个自定义TextBox
控件,该控件在为空时显示一个值,用作字段标签。例如,在地址表单中,这将在空的文本框中显示“客户姓名”。一旦用户输入控件,它将恢复为标准操作。当控件离开时,如果值仍然为空,它将恢复到其掩码模式。
背景
有时您需要使表单尽可能紧凑,这要求您没有任何额外的标签控件来描述您的文本框。该控件允许标签本身在控件内部(为空时),以便用户知道在哪里输入信息。
使用代码
因此,提供的代码几乎可以直接使用,但涉及的方法将让您了解这是如何完成的。您可以创建自己的自定义控件,并进行较少的自定义,或者也许从中获得启发,进行更多自定义。
这是类的代码。
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace BuckSoft.Controls
{
public partial class EmptyTemplateTextBox : TextBox
{
private String _emptyvalue;
private Color _emptyforecolor;
private Color _activeforecolor;
private bool _preservebindings;
public EmptyTemplateTextBox()
{
_preservebindings = true;
InitializeComponent();
}
public String EmptyValue
{
get
{
return _emptyvalue;
}
set
{
if ((Text == _emptyvalue) && (!Focused))
{
Text = value;
ForeColor = _emptyforecolor;
}
_emptyvalue = value;
}
}
public Color EmptyForeColor
{
get
{
return _emptyforecolor;
}
set
{
if (Text == _emptyvalue)
{
ForeColor = value;
}
_emptyforecolor = value;
}
}
public Color ActiveForeColor
{
get
{
return _activeforecolor;
}
set
{
if (Text != _emptyvalue)
{
ForeColor = value;
}
_activeforecolor = value;
}
}
public bool PreserveBindingsOnEmpty
{
get { return _preservebindings; }
set { _preservebindings = value; }
}
protected override void OnTextChanged(EventArgs e)
{
if ((Text == String.Empty) && (!Focused))
{
Text = _emptyvalue;
ForeColor = _emptyforecolor;
}
else ForeColor = _activeforecolor;
base.OnTextChanged(e);
}
protected override void OnEnter(EventArgs e)
{
if (Text == _emptyvalue)
{
Text = String.Empty;
ForeColor = _activeforecolor;
}
base.OnEnter(e);
}
protected override void OnGotFocus(EventArgs e)
{
if (Text == _emptyvalue)
{
Text = String.Empty;
ForeColor = _activeforecolor;
}
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e)
{
if (Text == String.Empty)
{
if (_preservebindings)
{
foreach (Binding b in DataBindings)
{
b.BindingComplete +=
new BindingCompleteEventHandler(binding_BindingComplete);
}
}
else
{
Text = _emptyvalue;
ForeColor = _emptyforecolor;
}
}
base.OnLeave(e);
}
private void binding_BindingComplete(object sender, BindingCompleteEventArgs e)
{
if (Text == String.Empty)
{
Text = _emptyvalue;
ForeColor = _emptyforecolor;
}
}
}
}
请注意,由于我们从 UserControl 开始,我们需要更改以下行
public partial class EmptyTemplateTextBox : UserControl
修改为:
public partial class EmptyTemplateTextBox : TextBox
由于我们从 UserControl
开始,我们需要稍微调整 EmptyTemplateTextBox.Designer.cs 文件。
首先,在设计器生成的代码部分,删除以下行:
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
因此,设计器将为我们的新属性 EmptyValue
、EmptyForeColor
和 ActiveForeColor
提供一些初始值,添加以下行:
_preservebindings = false;
_emptyvalue = string.Empty;
_emptyforecolor = System.Drawing.SystemColors.ScrollBar;
_activeforecolor = System.Drawing.SystemColors.ControlText;
您也可以在 InitializeCompenents()
调用之前的构造函数中放入这些行。
我们需要为该控件添加的三个属性是:
EmptyValue
- 当TextBox
为空时将显示给用户的值。EmptyForeColor
- 空标签将显示的颜色值,最好是某种浅色调,我选择了SystemColors.ScrollBar
。ActiveForeColor
- 用户输入的文本将显示的颜色值,我选择了默认的SystemColors.ControlText
。
在定义这些属性时,我们必须确保在更改它们时,会发生某些事情以保持所需行为的连续性。
EmptyValue
public String EmptyValue
{
get
{
return _emptyvalue;
}
set
{
if ((Text == _emptyvalue) && (!Focused))
{
Text = value;
ForeColor = _emptyforecolor;
}
_emptyvalue = value;
}
}
get { }
只需返回 EmptyValue
的值。
如果 EmptyValue
是 set { }
以编程方式设置,我们希望确保控件已更新以显示,但在设置新值之前,我们需要检查旧的 EmptyValue
是否为当前值,如果是,则需要显示新的 EmptyValue
。(!Focused) 确保显示更改仅在 TextBox
未使用时发生。
EmptyForeColor
public Color EmptyForeColor
{
get
{
return _emptyforecolor;
}
set
{
if (Text == _emptyvalue)
{
ForeColor = value;
}
_emptyforecolor = value;
}
}
设置此属性时,需要检查当前文本是否为 EmptyValue
,如果是,则设置新的 ForeColor
值。
ActiveForeColor
public Color ActiveForeColor
{
get
{
return _activeforecolor;
}
set
{
if (Text != _emptyvalue)
{
ForeColor = value;
}
_activeforecolor = value;
}
}
设置此属性时,只需检查 TextBox
的值是否不是 EmptyValue
,然后设置新的 ForeColor
值。
最后一个可选属性,一个布尔值 PreserveBindingsOnEmpty
,它将确保如果文本框已绑定数据,在显示空值时不会更新数据源。事实上,当文本框为空时失去焦点,它将恢复到原始绑定的值。有关如何实现此功能的说明,请参阅下面的 Leave 事件重写。
现在我们必须通过重写来劫持一些 TextBox
事件。
首先,我们需要重写 TextChanged
事件。
protected override void OnTextChanged(EventArgs e)
{
if ((Text == String.Empty) && (!Focused))
{
Text = _emptyvalue;
ForeColor = _emptyforecolor;
}
else ForeColor = _activeforecolor;
base.OnTextChanged(e);
}
如果文本框文本被以编程方式清空(即,在未聚焦时更改),那么我们需要填充 EmptyValue
,并设置 EmptyForeColor
。否则,ForeColor
需要是 ActiveForeColor
。
接下来,我们需要重写 Entered
和 GotFocus
事件,两者执行相同的功能。GotFocus
对于控件是表单加载时第一个聚焦的控件是必需的。
protected override void OnEnter(EventArgs e)
{
if (Text == _emptyvalue)
{
Text = String.Empty;
ForeColor = _activeforecolor;
}
base.OnEnter(e);
}
protected override void OnGotFocus(EventArgs e)
{
if (Text == _emptyvalue)
{
Text = String.Empty;
ForeColor = _activeforecolor;
}
base.OnEnter(e);
}
当 TextBox
获得焦点且显示 EmptyValue
时,文本将被清除,并设置 ActiveForeColor
。
最后,我们需要重写 Leave 和 LostFocus
事件,LostFocus
处理标签切换操作。为控件的每个 Binding 添加 BingingComplete
的事件处理程序,并调用 Binding.WriteValue
以确保 BindingComplete
被触发,有时仅失去焦点不会导致绑定。(!Focused) 再次确保我们在使用控件时不会将其设置为 EmptyValue
:
protected override void OnLeave(EventArgs e)
{
if (Text == String.Empty)
{
if (_preservebindings)
{
foreach (Binding b in DataBindings)
{
b.BindingComplete +=
new bindingCompleteEventHandler(binding_BindingComplete);
b.WriteValue();
}
}
else
{
Text = _emptyvalue;
ForeColor = _emptyforecolor;
}
}
base.OnLeave(e);
}
protected override void OnLostFocus(EventArgs e)
{
if (Text == String.Empty)
{
if (_preservebindings)
{
foreach (Binding b in DataBindings)
{
b.BindingComplete +=
new BindingCompleteEventHandler(binding_BindingComplete);
b.WriteValue();
}
}
else
{
Text = _emptyvalue;
ForeColor = _emptyforecolor;
}
}
base.OnLeave(e);
}
private void binding_BindingComplete(object sender, BindingCompleteEventArgs e)
{
if ((Text == String.Empty) && (!Focused))
{
Text = _emptyvalue;
ForeColor = _emptyforecolor;
}
}
当 TextBox
为空时失去焦点,数据源会用新的空文本更新 在 控件设置 EmptyValue
和 EmptyForeColor
之前。这一点很重要,因为否则,一旦设置了数据,您将无法从数据源中删除该值。此方法允许数据在为空时进行绑定,然后在绑定完成后,我们处理 EmptyValue
和 EmptyForeColor
值的设置。
我建议在表单中使用文本框时,用户习惯于在完成一个字段后按 Enter 键,而那个“叮”的声音可能很烦人。您可以通过以下处理程序拦截 KeyPress
来停止这种烦扰:
private void textBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter) e.Handled = true;
}
希望这能帮助到有人。