利用 C#制作一个仿IE地址栏的文本框
丽水市汽车运输集团有限公司信息中心苟安廷
利用 IE 上网时,只要在地址栏中输入几个字母,与这几个字母模糊匹配的地址就会自动显示出来供用户选择(如下图),用户通过按键盘上的上、下箭头在已有选项中遍历,找到自己需要的选项后,按回车键进行选择,也可以直接用鼠标进行操作,非常方便,我们在程序中也可以利用这一功能,实现自动提示,方便用户输入,下面就以一个实际例子介绍我在工作中是如何实现的。
从上图中可以看出,最佳的办法似乎就是继承 ComboBox 写一个控件,在 TextChanged 事件中,根据内容变化决定是否应拉下提示框,以及该提示什么内容,在实际工作中我们发现, ComboBox 非常难以控制,如修改了 SelectedIndex 属性后,会自动产生 TextChanged 事件,造成死循环等等,虽然可以添加其他一些变量来标记该文本改变是用户引起的还是由程序引起的以进行区别对待处理,但效果始终不理想,经过反复试验,最后选择了文本框 + 列表框的方式,并做成控件库供其他程序调用,效果很理想,其中,文本框接收用户输入,列表框提供选项让用户选择。
新建一个普通的 windows 应用程序用来测试,不妨取名为 Test 吧,然后单击菜单“文件”→“添加项目”→“新建项目( N )”,从弹出来的对话框选择“ windows 控件库”,将该项目和 Test 项目放在同一个文件夹中,不妨取名为“ TextBoxExt ”,该项目是本文的重点。
在“解决方案资源管理器” 中,右键单击“ TextBoxExt ”项目,从弹出的菜单中选择“属性”,会弹出属性配置对话框,在左上角的“配置( C )”中选择“所有配置”,设置输出路径为“ ..\output ”,注意,该输入有点特殊,两个小数点 + 反斜杠 +output ,意思是当前文件夹上一层的 ouput 文件夹(从 VC 过来的朋友可能比较熟悉这种方式),如下图:
编译一下,在“我的电脑”或“资源管理器”中我们可以就可以看到与 TextBoxExt 文件夹同一级自动创建了一个 output 文件夹,输出的 TextboxExt.dll 乖乖地躺在这里:
再来配置一下依赖性,点菜单“项目”→“设置依赖性( D )”,设置项目 Test 取决于“ TextBoxExt ”,至此,开发环境配置完毕。
在“解决方案资源管理器” 中双击“ UserControl1.cs ”文件,再切换到代码窗口中。为便于引用,我们将命名空间“ namespace TextBoxExt ”改为“ namespace Tools ”,由于本控件继承于文本框,因此,将代码
public class UserControl1 : System.Windows.Forms.UserControl
{
public UserControl1()
{
InitializeComponent();
}
修改为:
public class TextBoxExt : System.Windows.Forms.TextBox
{
private System.ComponentModel.Container components = null ;
public TextBoxExt()
{
}
也就是说将命名空间改为 Tools ,将类名改为 TextBoxExt ,让该类继承于 System.Windows.Forms.TextBox ,并修改相应的构造函数。编译成功后,在“解决方案资源管理器中”双击项目“ Test ”的“ Form1.cs ”来切换到窗体设计,在“工具箱”窗口中切换到“我的用户控件”选项中,在空白处单击右键,从弹出的菜单中选择“添加 / 移出项”,接下来会弹出一个对话框,点“浏览”按钮,找到刚才生成的控件库,如下图:
最后点“确定”按钮,在“工具箱”的“我的控件库”中就多了一个“ TextBoxExt ”控件,同操作普通文本框控件一样,在窗体上添加几个该自定义控件。可以看出,该文本框和平时使用的文本框目前完全一样。
切换到 UserControl1.cs 代码设计窗口中,添加一个列表框变量,用于显示提示:
private System.Windows.Forms.ListBox m_lstShowChoice= null ;
添加一段代码,用于响应列表框鼠标的 MouseUp 事件,也就是用户通过单击列表框进行选择:
private void lstBox_MouseUp( object sender, System.Windows.Forms.MouseEventArgs e)
{
ListBox box=(ListBox)sender;
if ((box.SelectedIndex>-1) && ! this .ReadOnly)
{
this .Text=box.SelectedItem.ToString();
//选择后文本框失去了焦点,这里移回来
this .Focus();
}
}
添加鼠标在列表框中移动的事件,当用户在列表框中移动鼠标时,根据鼠标位置,自动设置列表框当前项。
private void lstBox_MouseMove( object sender, System.Windows.Forms.MouseEventArgs e)
{
ListBox box=(ListBox)sender;
Point pt = new Point(e.X,e.Y);
int n=box.IndexFromPoint(pt);
if (n>=0)
box.SelectedIndex=n;
}
为了美观,可以设置列表框的前景、背景、边框风格等,按常规,我们可以设置一个 public 变量来供程序调用,但在程序设计时无法通过属性窗口直接修改,不方便,通过“性质”来引用可以解决,下面的代码是设置列表框的背景,比较好理解:
#region 设置提示框的背景
private Color m_lstForColor=System.Drawing.SystemColors.InfoText;
///
1<summary>
2
3/// 设置/获取提示的背景色
4
5/// </summary>
public Color PromptBackColor
{
get
{
return m_lstBackColor;
}
set
{
m_lstBackColor= value ;
//lstPrompt的创建见下面的代码
ListBox box= this .lstPrompt;
if (box!= null )
box.BackColor=m_lstBackColor;
}
}
#endregion
设置前景、边框的方法完全一样,不再赘述,经过这样处理,我们在程序设计时就可以直接在“属性”窗口中指定了,如下图:
接下来,也是通过“性质”来返回当前列表框,如果没有则创建:
private System.Windows.Forms.ListBox lstPrompt
{
get
{
//如果没有列表用于显示提示的列表框,则创建一个
if ((m_lstShowChoice== null ) && this .Parent!= null )
{
m_lstShowChoice= new ListBox();
m_lstShowChoice.Visible= false ;
m_lstShowChoice.Left= this .Left;
m_lstShowChoice.Top= this .Bottom;
m_lstShowChoice.Width= this .Width;
m_lstShowChoice.TabStop= false ;
m_lstShowChoice.Sorted= true ;
m_lstShowChoice.ForeColor= this .m_lstForColor; //前景
m_lstShowChoice.BackColor= this .m_lstBackColor; //背景(参见m_lstForColor的创建
m_lstShowChoice.BorderStyle= this .m_lstBordrStyle; //边框,背景(参见m_lstForColor的创建
//如果提示框过低,则显示到上面
if (m_lstShowChoice.Bottom> this .Parent.Height)
m_lstShowChoice.Top= this .Top-m_lstShowChoice.Height+8;
m_lstShowChoice.MouseUp += new System.Windows.Forms.MouseEventHandler( this .lstBox_MouseUp);
m_lstShowChoice.MouseMove+= new System.Windows.Forms.MouseEventHandler( this .lstBox_MouseMove);
this .Parent.Controls.Add(m_lstShowChoice);
this .Parent.ResumeLayout( false );
m_lstShowChoice.BringToFront();
}
return m_lstShowChoice;
}
}
创建一个 ArrayList 用于存放全部可供选择的项目:
private ArrayList m_ForChoice= new ArrayList();
public ArrayList ChoiceArray
{
get
{
return m_ForChoice;
}
set
{
m_ForChoice=(ArrayList)( value .Clone());
ListBox box= this .lstPrompt;
if (box!= null )
{
box.Items.Clear();
box.Items.AddRange(m_ForChoice.ToArray());
}
}
}
用户在输入时,经常喜欢加空格,如两个字的姓名“张三”,用户喜欢输成“张 三”,虽然可以和三个字的姓名对齐,比较美观,但对程序中姓名检索等非常不便,因为你还要判断中间是否有空格,有多少空格等,为此,我们设置一个“性质”来决定是否允许用户输入空格。
private bool m_AllowSpace= false ;
public bool AllowSpace
{
get
{
return m_AllowSpace;
}
<P class=MsoNormal style="MARGIN: