65.9K
CodeProject 正在变化。 阅读更多。
Home

空模板文本框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (4投票s)

2012年9月24日

CPOL

4分钟阅读

viewsIcon

26966

downloadIcon

332

本指南展示了如何扩展标准 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;

因此,设计器将为我们的新属性 EmptyValueEmptyForeColorActiveForeColor 提供一些初始值,添加以下行: 

_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 的值。

如果 EmptyValueset { } 以编程方式设置,我们希望确保控件已更新以显示,但在设置新值之前,我们需要检查旧的 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

接下来,我们需要重写 EnteredGotFocus 事件,两者执行相同的功能。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 为空时失去焦点,数据源会用新的空文本更新 控件设置 EmptyValueEmptyForeColor 之前。这一点很重要,因为否则,一旦设置了数据,您将无法从数据源中删除该值。此方法允许数据在为空时进行绑定,然后在绑定完成后,我们处理 EmptyValueEmptyForeColor 值的设置。 

我建议在表单中使用文本框时,用户习惯于在完成一个字段后按 Enter 键,而那个“叮”的声音可能很烦人。您可以通过以下处理程序拦截 KeyPress 来停止这种烦扰: 

private void textBox_KeyPress(object sender, KeyPressEventArgs e)
{
    if (e.KeyChar == (char)Keys.Enter) e.Handled = true;
}

希望这能帮助到有人。

© . All rights reserved.