// ********************************************************
// 自动完成控件
// Designed by Faib Studio.
// Copyright 2007
// Email faib920@126.com or QQ 55570729
// ********************************************************
using System;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Drawing;
using System.Drawing.Design;
namespace FaibClass.WebControls
{
[DefaultProperty("Text")]
[ParseChildren(true, "Items")]
[DefaultEvent("Changed")]
[ToolboxData("<{0}:AutoCompleteTextBox runat=server></{0}:AutoCompleteTextBox>")]
public class AutoCompleteTextBox : BaseTextBox, IPostBackDataHandler, IPostBackEventHandler
{
[Description("列表项改变时。")]
public event EventHandler Changed;
私有变量#region 私有变量
private ListItemCollection m_lics;
private int m_Rows = 8;
private bool m_SendKeyTab = false;
private bool m_MatchAnywhere = true;
private bool m_ListAllItemOnFocus = true;
private ListItem m_SelectedItem = null;
private int m_SelectedIndex = -1;
#endregion
public AutoCompleteTextBox()
{
m_lics = new ListItemCollection();
}
属性#region 属性
[Category("Appearance")]
[Description("文本值。")]
[PersistenceMode(PersistenceMode.Attribute)]
public override string Text
{
get{return base.Text;}
set{base.Text = value;}
}
[Category("Data")]
[Description("列表中项的集合。")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[NotifyParentProperty(true)]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public ListItemCollection Items
{
get{return m_lics;}
}
[Category("Appearance")]
[Description("列表显示的行数。")]
[DefaultValue(8)]
public new int Rows
{
get{return m_Rows;}
set{m_Rows = value;}
}
[Category("Behavior")]
[Description("按回车选择时是否发移到下一控件。")]
[DefaultValue(false)]
public bool SendKeyTab
{
get{return m_SendKeyTab;}
set{m_SendKeyTab = value;}
}
[Category("Behavior")]
[Description("是否匹配任意位置的字符串。")]
[DefaultValue(true)]
public bool MatchAnywhere
{
get{return m_MatchAnywhere;}
set{m_MatchAnywhere = value;}
}
[Category("Behavior")]
[Description("是否在获得焦点时列出所有项。")]
[DefaultValue(true)]
public bool ListAllItemOnFocus
{
get{return m_ListAllItemOnFocus;}
set{m_ListAllItemOnFocus = value;}
}
[Browsable(false)]
[Description("返回被选中项。")]
public ListItem SelectedItem
{
get{return m_SelectedItem;}
}
[Browsable(false)]
[Description("返回被选中项的索引。")]
[DefaultValue(-1)]
public int SelectedIndex
{
get{return m_SelectedIndex;}
set{
m_SelectedIndex = value;
m_SelectedItem = m_lics[m_SelectedIndex];
this.Text = m_SelectedItem.Text;
}
}
internal new TextBoxMode TextMode
{
get{return TextBoxMode.SingleLine;}
}
internal new bool Wrap
{
get{return false;}
}
internal new int MaxLength
{
get{return 0;}
}
internal new int Columns
{
get{return 0;}
}
#endregion
公有方法#region 公有方法
protected override void OnInit(EventArgs e)
{
if (Page != null)
{
//将控件注册为需要回发处理的控件
Page.RegisterRequiresPostBack(this);
}
base.OnInit (e);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender (e);
if (Page != null)
{
//注册隐藏字段,用于保存客户端选择的索引及对Items的修改
Page.RegisterHiddenField("__" + this.ClientID + "_State__", m_SelectedIndex.ToString() + "※");
}
}
protected override void OnLoad(EventArgs e)
{
//注册一个js文件到缓存中
Util.RegisterCacheFile(Page, "AutoCompleteTextBox", "autocompleteTextbox.fbs.ashx", "Resource.AutoCompleteTextBox.js");
//输出控件初始化脚本
Util.RegisterStartupScript(Page, "AutoCompleteTextBox_" + this.ClientID, "\n<script>\nif(document.getElementById(\"" + this.ClientID + "\")){AutoCompleteBox_Init(document.getElementById(\"" + this.ClientID + "\"));}\n</script>");
//添加属性
Attributes.Add("rows", m_Rows.ToString());
if(AutoPostBack)Attributes.Add("autopostback", "1");
if(m_MatchAnywhere)Attributes.Add("matchanywhere", "1");
if(m_ListAllItemOnFocus)Attributes.Add("listallitemonfocus", "1");
if(m_SendKeyTab)Attributes.Add("sendkeytab", "1");
base.OnLoad (e);
}
protected override void Render(HtmlTextWriter output)
{
base.Render (output);
if(IsDesignMode)return;
//输出Items中的每一项生成fsc:ListItem标签
output.Write("<?XML:NAMESPACE PREFIX=\"fsc\" />");
output.AddAttribute("id", this.ClientID + "_items");
output.RenderBeginTag("fsc:AutoCompleteTextBox");
foreach(ListItem lt in m_lics)
{
output.WriteBeginTag("fsc:ListItem");
output.WriteAttribute("value", lt.Value);
output.WriteAttribute("text", lt.Text);
output.WriteLine(" />");
}
output.RenderEndTag();
}
[DescriptionAttribute("引发 PageIndexChanged 事件。")]
protected virtual void OnChanged()
{
if(Changed != null)
{
Changed(this, new EventArgs());
}
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState (savedState);
//将Items保存到ViewState,由于ListItem不支持序列化,所以需要使用自定义类来进行保存
if (ViewState["Items"] != null)
m_lics = Util.LoadListItemFromViewState(ViewState["Items"]);
}
protected override object SaveViewState()
{
//从ViewState中读取Items
ViewState["Items"] = Util.SaveListItemToViewState(m_lics);
return base.SaveViewState ();
}
#endregion
接口#region 接口
void IPostBackDataHandler.RaisePostDataChangedEvent()
{
}
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
//触发事件
if(eventArgument == "")
OnChanged();
}
bool IPostBackDataHandler.LoadPostData(String postDataKey, NameValueCollection values)
{
//处理回发数据
string value = values["__" + this.ClientID + "_State__"];
if (value != null)
{
string[] data = value.Split('※');//客户端Items的修改,使用saveState后生成的数据
if(data[1] != "")
{
m_lics.Clear();
for(int i = 1; i < data.Length; i++)
{
string[] da1 = data[i].Split('□');
m_lics.Add(new ListItem(da1[0], da1[1]));
}
SaveViewState();
}
if(values[this.ClientID].Length == 0)
{
m_SelectedIndex = -1;
m_SelectedItem = null;
}
else
{
if(data[0].CompareTo("-1") != 0)//选定项
{
try
{
m_SelectedIndex = int.Parse(data[0]);
m_SelectedItem = this.Items[m_SelectedIndex];
}
catch
{
throw;
}
}
}
}
this.Text = values[this.ClientID];
return false;
}
#endregion
}
}
此控件继承自BaseTextBox类,BaseTextBox是一个简单的类,目前只实现了一个属性:
protected internal virtual bool IsDesignMode
{
get { return (Site != null) ? Site.DesignMode : false; }
}
Javascript源代码见
http://www.cnblogs.com/faib/archive/2007/05/10/741875.html