AJAX是第 3部分: 自动完成文本框

分享于 

36分钟阅读

Web开发

  繁體 雙語

介绍

如果你一直关注这个系列文章,那么我们就会在第 1部分中了解到异步JavaScript和XML或者AJAX的简要介绍。 我们创建了 CallBackObject 来帮助简化回调启动过程。 在第1部分中,我们讨论了将 CallBackObject 与 ASP.NET 控件和事件集成起来。 下面,我们将把所有这些知识放在良好的使用中,并使用我们所学到的所有知识创建自定义的控件。 就像你可能猜到的,该控件是自动完成的TextBox ( ACTB )。

在我们获得好的内容之前,我想说有很多空间可以改进这个控制。 功能。设计时间集成和ease-of-use都可以得到极大的改进。 我把这个留给你 !

好东西

在我们讨论创建控件之前,我想要告诉你使用控件的容易程度。 我们将从清单 1和 2 ( actb.aspx 和 Actb.aspx. cs ) 开始。 在你静止自己的兴奋之后,我们将检查ACTB清单 3 ( autocompletetextbox.js ) 和 ASP.NET 部分清单 4 ( autocompletetextbox.cs )的JavaScript部分。

Actb.aspx

这一页很简单。 我们为用户设置一些输入字段。 大多数人可能会注意到,并非所有国家都使用邮政编码。 我将这里作为演示如何根据它的他字段的值自定义自动完成文本框的结果。 ( 稍后再说,) 要使用我们的自定义控件,我们必须使用页面对该程序集进行 register。 我使用了字母缩写作为标签前缀,但是你可以选择任何你想要的前缀。 我们还指定了可以在其中找到控件的命名空间和程序集 NAME。

<%@RegisterTagPrefix="wcp"Namespace="WCPierce.Web.UI.WebControls"Assembly="WCPierce.Web"%>

之后,唯一有趣的HTML Fragment就是 ACTB的实际声明。

<wcp:AutoCompleteTextBoxrunat="server"id="actbCountry"OnTextChanged="actbCountry_TextChanged"ListItemCssClass="ListItem"ListItemHoverCssClass="ListItemHover"/>

声明与普通 ASP TextBox的声明几乎相同。 唯一添加的属性是 ListItemCssClassListItemHoverCssClass,用于美化下拉列表。 这些CSS类是在外部样式表 AutoCompleteTextBox.css. 中定义

Actb.aspx.cs

当我们检查文件后面的代码时,事情开始变得更加有趣。 首先要注意的是 使用 代码顶部的语句:

... using Microsoft.ApplicationBlocks.Data;using WCPierce.Web;using WCPierce.Web.UI.WebControls;

Microsoft提供的数据应用程序 block 用于简化某些数据库访问代码。 另外两个 使用 指令使我们能够访问自动完成的文本框和 CallBackHelper 类。

注意我们在HTML中引用的actbCountry_TextChanged 事件。 这里函数中的所有内容都包装在 try / catch block 和任何错误都通过 CallBackHelper.HandleError 返回给客户端。

try{
 //... }catch(Exception ex)
{
 CallBackHelper.HandleError( ex );
}

因为在回调过程中发生的错误很难调试( 相信我),所以这一点很重要。 适当的代码和适当的JavaScript,使得调试错误变得轻而易举。

第一步是检查 txtZip 条目字段的内容。 如果在那里有一个值,actbCountry 将默认为"状态"( 对于使用邮政编码的它的他国家来说抱歉)。

if( txtZip.Text.Length >0 )
{
 CallBackHelper.Write( "United States" );
}

对于代码的下一部分,重要的是要记住每次用户在 ACTB 中按键时,这个事件是触发的。 因此,如果Zip字段是空的,那么我们将使用用户当前输入的内容,我们将使用"u",并搜索以字母"u"开头的每个国家。

AutoCompleteTextBox actb = s as AutoCompleteTextBox;string str = String.Format("SELECT [Text] 
 FROM Lists 
 WHERE ListName='Country' 
 AND [Text] LIKE '{0}%' 
 ORDER BY [Text]", actb.Text);

所有匹配的国家( 乌干达,乌克兰,乌拉圭,等等 ) 都在 SqlDataReader 中返回。 然后,我们将自动完成文本框的DataSource 属性设置为 SqlDataReader。 这里过程与绑定到 DropDownList 或者 DataGrid的过程相同。

SqlDataReader sdr = SqlHelper.ExecuteReader(@"Server=(local);
 Database=DotNetNuke;
 Integrated Security=SSPI;", 
 CommandType.Text, str);
actb.DataSource = sdr;
actb.DataTextField = "Text";
actb.BindData();

明智的读者会注意到,对 BindData()的调用是唯一的区别。 通常使用 DataBound 控件,你可以调用 DataBind()。 不幸的是,我无法使这项工作正常。 原因有点复杂,但是你可以看到为什么试图在 DataGrid 中使用自动完整的文本框来禁用视图。

就是这样我把 ACTB 控件中所有的硬盘都封装起来了。 你现在可以像其他任何数据绑定控件一样使用它。 浏览站点查看操作中的ACTB 演示。 把这个空的拉链放在空白处,输入一个字母,你就会看到一个下拉列表,以及第一个国家的自动完成。 贴心 !

AutoCompleteTextBox.js

在我们开始讨论这个小 gem 之前,我需要识别帮助我实现这个控制的大个人:

这两篇文章中的概念和 CallBackObject 产生了 ACTB。 这段代码中有很多代码,而不是讨论两篇文章中介绍的部分,我只是介绍新的内容。

AutoCompleteTextBox.prototype.TextBox_KeyUp = function(oEvent)
{
 var iKeyCode = oEvent.keyCode;
 if( iKeyCode == 8 )
 {
 this.Div.innerHTML = '';
 this.Div.style.display = 'none';
 return;
 }
 elseif( iKeyCode == 16 || iKeyCode == 20 )
 {
 this.DoAutoSuggest = true;
 }
 elseif (iKeyCode <32 || (iKeyCode> = 33 && iKeyCode <= 46) || 
 (iKeyCode> = 112 && iKeyCode <= 123)) 
 {
 return;
 }
 else {
 this.DoAutoSuggest = true;
 }
 var txt = this.TextBox.value;
 if( txt.length> 0 )
 {
 this.Cbo.DoCallBack(this.TextBox.name, txt);
 }
 else {
 this.Div.innerHTML = '';
 this.Div.style.display = 'none';
 this.Cbo.AbortCallBack();
 }
}

只要在 ACTB 中按下了键,这个事件就会触发。 我们进行一些检查以查看按下哪个键,如果在文本框中有任何数据。 如果是这样,我们将调用 Cbo.DoCallBack。 就像你从第1部分中所了解的,这就是启动服务器端请求的方法。

当服务器端请求完成时,我们的方法 AutoCompleteTextBox.prototype.Cbo_Complete 然后我们会处理结果。

AutoCompleteTextBox.prototype.Cbo_Complete = function(responseText, responseXML)
{ 
 while ( this.Div.hasChildNodes() )
 this.Div.removeChild(this.Div.firstChild);
 // get all the matching strings from the server responsevar aStr = responseText.split('n');
 // add each string to the popup-divvar i, n = aStr.length;
 if( n> 0 )
 {
 for ( i = 0; i <n; i++ )
 {
 var oDiv = document.createElement('div');
 this.Div.appendChild(oDiv);
 try {
 oDiv.innerHTML = aStr[i];
 }
 catch(e)
 {
 this.Cbo_Error('405','Error','Text returned from Call Back was invalid');
 return;
 }
 oDiv.noWrap = true;
 oDiv.style.width = '100%';
 oDiv.className = this.ListItemClass;
 oDiv.onmousedown = AutoCompleteTextBox.prototype.Div_MouseDown;
 oDiv.onmouseover = AutoCompleteTextBox.prototype.Div_MouseOver;
 oDiv.onmouseout = AutoCompleteTextBox.prototype.Div_MouseOut;
 oDiv.AutoCompleteTextBox = this; 
 }
 this.Div.style.display = 'block';
 if( this.DoAutoSuggest == true )
 this.AutoSuggest( aStr );
 } 
 else {
 this.Div.innerHTML = '';
 this.Div.style.display='none';
 }
}

从服务器返回的数据是一个新的行名分隔列表。 从下拉列表中删除任何当前条目后,将返回值拆分为国家名称的array。 然后,我们遍历 array 并添加每个县到下拉列表,分配一些事件,并设置任何样式。 然后将填充的列表显示给用户,我们调用 AutoSuggest 方法执行前面的类型并将第一个条目从文本框中选择。

我很抱歉,如果我在这部分上面 breezed,但在本节开头引用的文章解释代码的剩余部分。

AutoCompleteTextBox.cs

我试图在评论中彻底地理解自己。 我们将讨论控件的重点,以代替行( 我的手指tired了)的行。

首先要注意的是,AutoComplete文本框继承自内置的ASP。TextBox:

publicclass AutoCompleteTextBox : System.Web.UI.WebControls.TextBox

这会节省我们大量的工作。 ACTB 有许多附加属性用于指定一些CSS信息和用于事件的客户端部分的JavaScript文件的路径。 Render 方法是操作开始的地方:

protectedoverridevoid Render(HtmlTextWriter output)
{
 string uId = this.UniqueID;
 string newUid = uId.Replace(":", "_");
 string divId = newUid + "_Div";
 string jsId = newUid + "_Js";
 StringBuilder acScript = new StringBuilder();
 acScript.Append("<script type='"text/javascript"'>");
 acScript.AppendFormat("var {0} = new AutoCompleteTextBox('{1}','{2}');
 {0}.ListItemClass='{3}';
 {0}.ListItemHoverClass='{4}';", jsId, newUid, divId, 
 this.ListItemCssClass, this.ListItemHoverCssClass);
 acScript.Append("</script>");
 Page.RegisterStartupScript(newUid, acScript.ToString());
 base.Attributes.Add("AutoComplete", "False");
 base.Render(output);
 output.Write(String.Format("<DIV id={0}></DIV>", divId));
}

为了使客户端JavaScript工作,它需要一个对作为 ACTB的文本框的引用,以及它的作用。 <DIV> 将充当控件的下拉部分的标记。 ASP.NET 控件有一个 at,你通常在代码中使用,UniqueID 是页级别上控件的唯一标识符。 有时,ControlIDUniqueID 是相同的,但在用户控件。服务器控件或者 DataList 控件中使用控件时开始遇到问题。 因此,我们获取对 ACTBUniqueID的引用,并为我们 <DIV> 标记并在我们的动态JavaScript代码中使用。

string uId = this.UniqueID;string newUid = uId.Replace(":", "_");string divId = newUid + "_Div";string jsId = newUid + "_Js";

接下来我们动态创建客户端所需的JavaScript来创建自动完成的文本框。 在CSS属性的基础上初始化JavaScript对象,并让 ASP.NET 将它放在页面的适当位置,我们用 RegisterStartupScript

StringBuilder acScript = new StringBuilder();
acScript.Append("<script type='"text/javascript"'>");
acScript.AppendFormat("var {0} = new AutoCompleteTextBox('{1}','{2}');
 {0}.ListItemClass='{3}';
 {0}.ListItemHoverClass='{4}';", jsId, newUid, divId,
 this.ListItemCssClass, this.ListItemHoverCssClass);
acScript.Append("</script>");
Page.RegisterStartupScript(newUid, acScript.ToString());

最后,我们有了 类的( TextBox ) 呈现自身,然后呈现 <DIV> 拖放功能所需的标签:

base.Attributes.Add("AutoComplete", "False");base.Render(output);
output.Write(String.Format("<DIV id={0}></DIV>", divId));

我们还重写了 OnTextChanged 事件。 我们只希望在回调期间激发这里事件,只有当控件是事件的目标时,才会激发这里事件:

protectedoverridevoid OnTextChanged(EventArgs e)
{ 
 if( Page.Request.Params["__EVENTTARGET"] == 
 this.UniqueID && CallBackHelper.IsCallBack )
 {
 base.OnTextChanged( e );
 }
}

最后要处理的是 AutoPostBackDataBind。 如果启用 AutoPostBack,我们就会破坏AJAX的用途。 必须重写 DataBind 方法以消除它的功能。 如果你们中的一个知道如何让它工作,请让我知道。 现在,开发人员必须调用 BindData

publicoverridevoid DataBind()
{
 // Do Nothing}publicoverridebool AutoPostBack
{
 get { returnfalse; }
}publicvirtualvoid BindData()
{
 this.OnDataBinding(EventArgs.Empty);
}

结束语

最终我们的劳动成果提供了一个简洁的控制,给 ASP.NET 网站带来了一些新的功能。 有很多代码要摘要,我鼓励你下载源代码并播放。 我希望我奠定了工作的基础,并为将来的发展。 这种技术有很多潜在的潜力,而且 finally 得到了应该注意的注意事项。

清单 1 - Actb.aspx

<%@RegisterTagPrefix="wcp"Namespace="WCPierce.Web.UI.WebControls"Assembly="WCPierce.Web"%><%@Pagelanguage="c#"Codebehind="Actb.aspx.cs"AutoEventWireup="false"Inherits="TestWeb.Actb"%><!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN"><HTML><HEAD><title>AutoCompleteTextBox Example</title><metaname=vs_defaultClientScript content="JavaScript"><metaname=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5"><linkhref="Css/AutoCompleteTextBox.css"type="text/css"rel="stylesheet"/></HEAD><body><formid="Form1"method="post"runat="server"><table><tr><tdcolspan="2">Please enter your informaiton below.</td></tr><tr><td>Name:</td><td><asp:TextBoxRunat="server"ID="txtName"/></td></tr><tr><td>Zip:</td><td><asp:TextBoxRunat="server"ID="txtZip"/></td></tr><tr><td>Country:</td><td><wcp:AutoCompleteTextBoxrunat="server"id="actbCountry"OnTextChanged="actbCountry_TextChanged"ListItemCssClass="ListItem"ListItemHoverCssClass="ListItemHover"/></td></tr></table></form></body></HTML>

清单 2 - Actb.aspx. cs

using System;using System.Collections;using System.ComponentModel;using System.Data;using System.Data.SqlClient;using System.Drawing;using System.Web;using System.Web.SessionState;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.HtmlControls;using Microsoft.ApplicationBlocks.Data;using WCPierce.Web;using WCPierce.Web.UI.WebControls;namespace TestWeb
{
 publicclass Actb : System.Web.UI.Page
 {
 protected System.Web.UI.WebControls.TextBox txtName;
 protected WCPierce.Web.UI.WebControls.AutoCompleteTextBox actbCountry;
 protected System.Web.UI.WebControls.TextBox txtZip;
 privatevoid Page_Load(object sender, System.EventArgs e) { }
 protectedvoid actbCountry_TextChanged(object s, EventArgs e)
 {
 try {
 if( txtZip.Text.Length >0 )
 {
 CallBackHelper.Write( "United States" );
 }
 else {
 AutoCompleteTextBox actb = s as AutoCompleteTextBox;
 string str = String.Format("SELECT [Text] 
 FROM Lists 
 WHERE ListName='Country' 
 AND [Text] LIKE '{0}%' 
 ORDER BY [Text]", actb.Text);
 SqlDataReader sdr = SqlHelper.ExecuteReader(@"Server=(local);
 Database=DotNetNuke;
 Integrated Security=SSPI;", 
 CommandType.Text, str);
 actb.DataSource = sdr;
 actb.DataTextField = "Text";
 actb.BindData();
 }
 }
 catch(Exception ex)
 {
 CallBackHelper.HandleError( ex );
 }
 }
 #region Web Form Designer generated code }
}

清单 3 - AutoCompleteTextBox.js

function AutoCompleteTextBox(TextBoxId, DivId, DivClass)
{
 // initialize member variablesvar oThis = this;
 var oText = document.getElementById(TextBoxId);
 var oDiv = document.getElementById(DivId);
 this.TextBox = oText;
 this.Div = oDiv;
 // CallBackObject + Event Handlersthis.Cbo = new CallBackObject();
 this.Cbo.OnComplete = function(responseText,responseXML)
 {oThis.Cbo_Complete(responseText,responseXML);};
 this.Cbo.OnError = function(status,statusText,responseText)
 {oThis.Cbo_Error(status,statusText,responseText);};
 // attach handlers to the TextBox oText.AutoCompleteTextBox = this;
 oText.onkeyup = AutoCompleteTextBox.prototype.OnKeyUp;
 oText.onblur = AutoCompleteTextBox.prototype.OnBlur;
 // align the drop down divvar c = GetCoords(oText);
 var n = oText.style.pixelHeight;
 if(!n )
 { 
 n = 25;
 }
 else {
 n += 2;
 }
 oDiv.style.left = c.x;
 oDiv.style.top = c.y + n;
 oDiv.style.display = 'none';
 oDiv.style.position = 'absolute';
 // Set some default stylesif( DivClass )
 oDiv.className = DivClass;
 else {
 oDiv.style.border = '1';
 oDiv.style.borderColor = 'black';
 oDiv.style.borderStyle = 'solid';
 oDiv.style.backgroundColor = 'white';
 oDiv.style.padding = '2';
 }
}
AutoCompleteTextBox.prototype.DoAutoSuggest = false;
AutoCompleteTextBox.prototype.ListItemClass = '';
AutoCompleteTextBox.prototype.ListItemHoverClass = '';// TextBox OnBlurAutoCompleteTextBox.prototype.OnBlur = function()
{
 this.AutoCompleteTextBox.TextBox_Blur();
}
AutoCompleteTextBox.prototype.TextBox_Blur = function()
{
 this.Div.style.display='none';
}// TextBox OnKeyUpAutoCompleteTextBox.prototype.OnKeyUp = function(oEvent)
{
 //check for the proper location of the event objectif (!oEvent) 
 {
 oEvent = window.event;
 } 
 this.AutoCompleteTextBox.TextBox_KeyUp(oEvent); 
}
AutoCompleteTextBox.prototype.TextBox_KeyUp = function(oEvent)
{
 var iKeyCode = oEvent.keyCode;
 if( iKeyCode == 8 )
 {
 this.Div.innerHTML = '';
 this.Div.style.display = 'none';
 return;
 }
 elseif( iKeyCode == 16 || iKeyCode == 20 )
 {
 this.DoAutoSuggest = true;
 }
 elseif (iKeyCode <32 || (iKeyCode> = 33 && iKeyCode <= 46) || 
 (iKeyCode> = 112 && iKeyCode <= 123)) 
 {
 return;
 }
 else {
 this.DoAutoSuggest = true;
 }
 var txt = this.TextBox.value;
 if( txt.length> 0 )
 {
 this.Cbo.DoCallBack(this.TextBox.name, txt);
 }
 else {
 this.Div.innerHTML = '';
 this.Div.style.display = 'none';
 this.Cbo.AbortCallBack();
 }
}
AutoCompleteTextBox.prototype.Cbo_Complete = 
 function(responseText, responseXML)
{ 
 while ( this.Div.hasChildNodes() )
 this.Div.removeChild(this.Div.firstChild);
 // get all the matching strings from the server responsevar aStr = responseText.split('n');
 // add each string to the popup-divvar i, n = aStr.length;
 if( n> 0 )
 {
 for ( i = 0; i <n; i++ )
 {
 var oDiv = document.createElement('div');
 this.Div.appendChild(oDiv);
 try {
 oDiv.innerHTML = aStr[i];
 }
 catch(e)
 {
 this.Cbo_Error('405','Error', 
 'Text returned from Call Back was invalid');
 return;
 }
 oDiv.noWrap = true;
 oDiv.style.width = '100%';
 oDiv.className = this.ListItemClass;
 oDiv.onmousedown = AutoCompleteTextBox.prototype.Div_MouseDown;
 oDiv.onmouseover = AutoCompleteTextBox.prototype.Div_MouseOver;
 oDiv.onmouseout = AutoCompleteTextBox.prototype.Div_MouseOut;
 oDiv.AutoCompleteTextBox = this; 
 }
 this.Div.style.display = 'block';
 if( this.DoAutoSuggest == true )
 this.AutoSuggest( aStr );
 } 
 else {
 this.Div.innerHTML = '';
 this.Div.style.display='none';
 }
}
AutoCompleteTextBox.prototype.Cbo_Error = 
 function(status, statusText, responseText)
{
 alert('CallBackObject Error: status=' + status + 'nstatusText=' + 
 statusText + 'n' + responseText);
}
AutoCompleteTextBox.prototype.Div_MouseDown = function()
{
 this.AutoCompleteTextBox.TextBox.value = this.innerHTML;
}
AutoCompleteTextBox.prototype.Div_MouseOver = function()
{
 if( this.AutoCompleteTextBox.ListItemHoverClass.length> 0 )
 this.className = this.AutoCompleteTextBox.ListItemHoverClass;
 else {
 this.style.backgroundColor = 'black';
 this.style.color = 'white';
 }
}
AutoCompleteTextBox.prototype.Div_MouseOut = function()
{
 if( this.AutoCompleteTextBox.ListItemClass.length> 0 )
 this.className = this.AutoCompleteTextBox.ListItemClass;
 else {
 this.style.backgroundColor = 'white';
 this.style.color = 'black';
 }
}
AutoCompleteTextBox.prototype.AutoSuggest = 
 function(aSuggestions /*:array*/) 
{
 if (aSuggestions.length> 0) 
 {
 this.TypeAhead(aSuggestions[0]);
 }
}
AutoCompleteTextBox.prototype.TypeAhead = 
 function( sSuggestion /*:string*/)
{
 if( this.TextBox.createTextRange || this.TextBox.setSelectionRange)
 {
 var iLen = this.TextBox.value.length; 
 this.TextBox.value = sSuggestion; 
 this.SelectRange(iLen, sSuggestion.length);
 }
}
AutoCompleteTextBox.prototype.SelectRange = 
 function (iStart /*:int*/, iLength /*:int*/) 
{
 //use text ranges for Internet Explorerif (this.TextBox.createTextRange) 
 {
 var oRange = this.TextBox.createTextRange(); 
 oRange.moveStart("character", iStart); 
 oRange.moveEnd("character", iLength - this.TextBox.value.length); 
 oRange.select();
 //use setSelectionRange() for Mozilla } 
 elseif (this.TextBox.setSelectionRange) 
 {
 this.TextBox.setSelectionRange(iStart, iLength);
 } 
 //set focus back to the textboxthis.TextBox.focus(); 
}function GetCoords(obj /*:object*/) 
{ 
 var newObj = new Object();
 newObj.x = obj.offsetLeft;
 newObj.y = obj.offsetTop;
 theParent = obj.offsetParent;
 while(theParent!= null)
 {
 newObj.y += theParent.offsetTop;
 newObj.x += theParent.offsetLeft;
 theParent = theParent.offsetParent;
 }
 return newObj;
}

清单 4 - AutoCompleteTextBox.cs

using System;using System.Collections;using System.Collections.Specialized;using System.Text;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.ComponentModel;using WCPierce.Web.UI;
[assembly:TagPrefix("WCPierce.Web.UI.WebControls", "wcp")]namespace WCPierce.Web.UI.WebControls
{
 ///<SUMMARY>/// AutoCompleteTextBox is similar to the WinForm /// ComboBox control. As the /// user types into the box, the enter is ///"auto-completed" based on values /// databound to the TextBox by the developer.///</SUMMARY> [DefaultProperty("Text"), 
 ToolboxData("<{0}:AutoCompleteTextBox runat="server">")]
 publicclass AutoCompleteTextBox : System.Web.UI.WebControls.TextBox
 {
 #region Member Variables///<SUMMARY>/// The (relative) path to the AutoCompleteTextBox JavaScript file.///</SUMMARY>privatestring _scriptPath = string.Empty;
 ///<SUMMARY>/// For using databinding with your AutoCompleteTextBox///</SUMMARY>privateobject _dataSource = null;
 ///<SUMMARY>/// Data returned to the client is in /// the form of"entry"-newline-///"entry"-newline...If you wanted to get /// cute, we could return in an XML/// format.///</SUMMARY>privatestaticreadonlystring _FormatString = "{0}n";
 ///<SUMMARY>/// If a ScriptPath isn't specified, check the /// web.config file for the /// following key.///</SUMMARY>privatestaticreadonlystring _ScriptPath = 
 "AutoCompleteTextBox.ScriptPath";
 ///<SUMMARY>/// CSS Class name for the list item of the dropdownlist.///</SUMMARY>privatestring _listItemCssClass = string.Empty;
 ///<SUMMARY>/// CSS Class name for the"hover" effect of /// the list item of the dropdownlist.///</SUMMARY>privatestring _listItemHoverCssClass = string.Empty;
 #endregion#region Public Properties///<SUMMARY>/// The path to the AutoComplete.js file. /// If you leave it blank, it will/// automatically look in the web.config /// for the value under the key///"AutoCompleteTextBox.ScriptPath". /// Should be a path relative to the /// application root i.e."~scriptsAutoCompleteTextBox.js".///</SUMMARY>publicstring ScriptPath
 {
 get 
 { 
 if( _scriptPath!= string.Empty )
 return ResolveUrl(_scriptPath); 
 try {
 return 
 ResolveUrl(System.Configuration.ConfigurationSettings.AppSettings[
 AutoCompleteTextBox._ScriptPath]);
 }
 catch 
 { 
 returnnull;
 }
 }
 set { _scriptPath = value; }
 }
 ///<SUMMARY>/// CSS Class name for the list item of the dropdownlist.///</SUMMARY>publicstring ListItemCssClass
 {
 get { return _listItemCssClass; }
 set { _listItemCssClass = value; }
 }
 ///<SUMMARY>/// CSS Class name for the"hover" effect of the /// list item of the dropdownlist.///</SUMMARY>publicstring ListItemHoverCssClass
 {
 get { return _listItemHoverCssClass; }
 set { _listItemHoverCssClass = value; }
 }
 ///<SUMMARY>/// For use with databinding.///</SUMMARY> [Bindable(true), 
 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
 DefaultValue((string) null)]
 publicvirtualobject DataSource
 {
 get {
 return _dataSource;
 }
 set {
 if (((value!= null) &&!(valueis IListSource)) && 
!(valueis IEnumerable))
 {
 thrownew ArgumentException("Invalid_DataSource_Type:" + 
 this.ID);
 }
 _dataSource = value;
 }
 }
 ///<SUMMARY>/// For use with databinding.///</SUMMARY>publicvirtualstring DataTextField
 {
 get 
 { 
 object o = this.ViewState["DataTextField"];
 if (o!= null)
 {
 return (string)o;
 }
 returnstring.Empty;
 }
 set {
 this.ViewState["DataTextField"] = value;
 }
 }
 ///<SUMMARY>/// For use with databinding.///</SUMMARY>publicvirtualstring DataTextFormatString
 {
 get {
 object o = this.ViewState["DataTextFormatString"];
 if (o!= null)
 {
 return (string)o;
 }
 returnstring.Empty;
 }
 set {
 this.ViewState["DataTextFormatString"] = value;
 }
 }
 ///<SUMMARY>/// For use with databinding.///</SUMMARY> [DefaultValue("")]
 publicvirtualstring DataMember
 {
 get {
 object o = this.ViewState["DataMember"];
 if (o!= null)
 {
 return (string)o;
 }
 returnstring.Empty;
 }
 set {
 this.ViewState["DataMember"] = value;
 }
 }
 #endregion#region Overrides///<SUMMARY>/// Render this control to the output parameter specified.///</SUMMARY>///<PARAMname="output">The HTML writer /// to write out to.</PARAM>protectedoverridevoid Render(HtmlTextWriter output)
 {
 string uId = this.UniqueID;
 string newUid = uId.Replace(":", "_");
 string divId = newUid + "_Div";
 string jsId = newUid + "_Js";
 StringBuilder acScript = new StringBuilder();
 acScript.Append("<script type='"text/javascript"'>");
 acScript.AppendFormat("var {0} = 
 new AutoCompleteTextBox('{1}','{2}');
 {0}.ListItemClass='{3}';
 {0}.ListItemHoverClass='{4}';", jsId, newUid, divId, 
 this.ListItemCssClass, this.ListItemHoverCssClass);
 acScript.Append("</script>");
 Page.RegisterStartupScript(newUid, acScript.ToString());
 base.Attributes.Add("AutoComplete", "False");
 base.Render(output);
 output.Write(String.Format("<DIV id={0}></DIV>", divId));
 }
 ///<SUMMARY>/// Register our common scripts and do default PreRendering.///</SUMMARY>///<PARAMname="e"></PARAM>protectedoverridevoid OnPreRender(EventArgs e)
 {
 this._RegisterCommonScripts();
 base.OnPreRender(e);
 }
 ///<SUMMARY>/// Only fire the OnTextChanged event if /// this control is the target and it/// is a Call Back///</SUMMARY>///<PARAMname="e"></PARAM>protectedoverridevoid OnTextChanged(EventArgs e)
 { 
 if( Page.Request.Params["__EVENTTARGET"] == 
 this.UniqueID && CallBackHelper.IsCallBack )
 {
 base.OnTextChanged( e );
 }
 }
 ///<SUMMARY>/// The original idea was to have the /// Auto Complete Text Box behave like a/// normal Data Bindable control. /// But, alas, I couldn't figure that out./// Thank you M$ for the databinding code.///</SUMMARY>///<PARAMname="e"></PARAM>protectedoverridevoid OnDataBinding(EventArgs e)
 {
 base.OnDataBinding(e);
 IEnumerable ie = 
 DataSourceHelper.GetResolvedDataSource(this.DataSource, 
 this.DataMember);
 StringBuilder sb = new StringBuilder();
 if( ie!= null )
 {
 bool useTextField = false;
 bool useFormatString = false;
 string textField = DataTextField;
 string formatString = DataTextFormatString;
 if( textField.Length!= 0 )
 {
 useTextField = true;
 }
 if( formatString.Length!= 0 )
 {
 useFormatString = true;
 }
 foreach( object o in ie )
 {
 if( useTextField )
 {
 if( textField.Length >0)
 {
 sb.AppendFormat(AutoCompleteTextBox._FormatString, 
 DataBinder.GetPropertyValue(o, textField, formatString));
 }
 }
 else {
 if( useFormatString )
 {
 sb.AppendFormat( AutoCompleteTextBox._FormatString, 
 string.Format(formatString, o) );
 }
 else {
 sb.AppendFormat(AutoCompleteTextBox._FormatString, 
 o.ToString());
 }
 } // useTextField } // foreach } // ie!= null// Remove trailing 'n'if( sb.Length >1 )
 sb.Remove(sb.Length-1, 1);
 CallBackHelper.Write( sb.ToString() );
 }
 ///<SUMMARY>/// Perhaps in the future, I will figure out /// how to make this work. Before/// you email me with the answer please try /// using an AutoCompleteTextBox in/// a DataGrid with ViewState disabled.///</SUMMARY>publicoverridevoid DataBind()
 {
 // Do Nothing }
 ///<SUMMARY>/// What's the point if the developer turns on AutoPostBack?///</SUMMARY>publicoverridebool AutoPostBack
 {
 get { returnfalse; }
 }
 #endregion#region Public Methods///<SUMMARY>/// For now, Developer's must call this method to bind to their /// Auto Complete Text Box.///</SUMMARY>publicvirtualvoid BindData()
 {
 this.OnDataBinding(EventArgs.Empty);
 }
 #endregion#region Helper Methods///<SUMMARY>/// Add a reference to the JavaScript, but only once per page.///</SUMMARY>privatevoid _RegisterCommonScripts()
 {
 if (!this.Page.IsClientScriptBlockRegistered("AutoCompleteTextBox"))
 {
 StringBuilder script = new StringBuilder();
 script.AppendFormat("<script src="{0}" type=text/javascript></script>", 
 this.ScriptPath);
 this.Page.RegisterClientScriptBlock("AutoCompleteTextBox", 
 script.ToString());
 }
 }
 #endregion }
}

历史记录

  • 2005-05-02
    • 初始版本。

COM  PAR  AUTO  文本  TEX  Complete  
相关文章