将 zichun 的自动完成文本框控件转换为 .NET ASCX 用户控件
本文介绍了我如何将 JavaScript 自动完成文本框转换为 .NET 用户控件,该控件可以轻松地以编程方式设置项。
引言
我有一个需求,即在客户打电话时能够快速记录通话历史记录;该记录将被实现为 .NET 主页页脚的一部分;从而出现在网站的每个页面上。由于系统中客户超过 500 位,下拉列表会过大,并且在主页页脚中引入某种搜索引擎会过于复杂。
我偶然发现了一篇由 zichun 撰写的 CodeProject 文章,在此。它还包含一个演示,实现了我想要的功能;但它是用 JavaScript 实现的,并且要求自动完成下拉列表的条目在脚本中预先指定,这对我需要的内容(来自数据库的动态字符串列表)来说不太理想。
本文介绍了我如何将此控件实现为 .NET 用户控件,该控件可以拖放到任何需要的 ASPX 网页上,并可以轻松地以编程方式动态设置其项列表。
致谢
感谢 CodeProject 的 zichun 提供了上述原始文章。所有的 JavaScript 代码都是他的;而且非常出色。
实现
第一件事是在我的项目中包含两个 JavaScript 文件。有关这些文件的更多信息,您可以参阅此文章的原始版本,在此。我在项目根目录下创建了一个名为App_Javascript的文件夹(只是为了遵循 .NET 命名约定),并包含了actb.js和common.js;这两者都由 zychun 编写,我对此不作任何评价。
接下来,我创建了一个/Controls文件夹,并在其中添加了一个名为AutoCompleteTextBox.ascx的新 .NET 用户控件。首先要创建标记。只需要一个TextBox
控件(用户将在其中输入他们想要自动完成的内容)和一个Literal
,用于输出包含项的脚本标签,这些项将作为自动完成选项出现。因此,AutoCompleteTextBox.ascx的内容是
<asp:TextBox id="txtTheTextbox" runat="server" />
<asp:Literal id="litTheJS" runat="server" />
接下来要做的是在此用户控件的Page_Init
中编写一些代码,如果页面head
标签中不存在这些脚本文件,则在该标签中写入对common.js和actb.js的引用。这意味着这些引用仅出现在使用此控件的页面中,并且永远不会被意外遗漏。为此,我只需检查页面标题中是否存在Literal
;如果不存在,则创建一个并像这样添加
请注意,这依赖于文件位于应用程序根目录的App_Javascript文件夹中,请根据需要进行更改
Protected Sub Page_Init(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Init
' Register the JS which is needed (if it has not been added before):
If IsNothing(Me.Page.Header.FindControl("litAutocompleteTextBoxSrc")) Then
Dim lit As New Literal
lit.ID = "litAutocompleteTextBoxSrc"
lit.Text = vbCrLf + String.Format("<script language="'javascript'"" &_
" type='text/javascript' src='{0}'></script>", _
Server.MapPath("~/App_Javascript/actb.js"))
lit.Text += vbCrLf + String.Format("<script language="'javascript'"" &_
" type='text/javascript' src='{0}'></script>", _
Server.MapPath("~/App_Javascript/common.js"))
lit.Text += vbCrLf
Me.Page.Header.Controls.Add(lit)
End If
End Sub
现在,.js文件已包含在已呈现的 ASPX 页面的标题标签中,接下来的工作就是提供两个属性来获取/设置TextBox
控件的文本和宽度
Public Property Text() As String
Get
Return Me.txtTheTextbox.Text
End Get
Set(ByVal value As String)
Me.txtTheTextbox.Text = value
End Set
End Property
Public Property Width() As Unit
Get
Return Me.txtTheTextbox.Width
End Get
Set(ByVal value As Unit)
Me.txtTheTextbox.Width = value
End Set
End Property
现在,我添加了一个名为Items
的只写属性,它是一个字符串数组。我将其实现为WriteOnly
,因为我希望能够随时更改或设置这些项。但是,我没有看到任何实际需要读取字符串项数组的理由,因此将其实现为只写,以免我尝试读取它们并对为什么会得到 null/空字符串数组感到困惑!
诀窍在于,此属性将字符串数组对象转换为 JavaScript 使用的字符串,作为其项数组。因此,一个包含单词 apple、orange 和 banana 的字符串数组会被转换为长字符串 'apple','orange','banana',包括所有的 ' 符号。
然后将此长字符串存储在 ViewState 变量中,该变量稍后在渲染 JavaScript 时使用
Public WriteOnly Property Items() As String()
Set(ByVal value As String())
Dim ItemsString As String = String.Empty
For Each s As String In value
ItemsString += "'" & s & "',"
Next
' Remove the training comma
ItemsString = ItemsString.Substring(0, ItemsString.Length - 1)
ViewState("TheItems") = ItemsString
End Set
End Property
最后,我的最后一个技巧是将我们在标记中定义的 Literal 的内容设置为使自动完成下拉列表正常工作的 JavaScript。我是在控件的 Page_Load 事件中执行此操作的;并简单地使用了上面创建的.Items
属性设置的 ViewState 变量的内容。这还会调用 (在其中一个 JavaScript 文件中定义的) actb
函数,使用TextBox
的ClientID
将下拉列表“附加”到TextBox
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
Me.litTheJS.Text = String.Format("<script type='text/javascript'> " &_
"var customarray = new Array({1}); " &_
"actb(document.getElementById('{0}'),customarray); </script>",
Me.txtTheTextbox.ClientID, ViewState("TheItems"))
End Sub
就这样!控件现在可以使用了。
使用控件
要使用该控件,只需在页面的标记(例如.aspx或.master)中像使用任何自定义用户控件一样添加对其的引用。(也可以通过将控件从解决方案资源管理器拖放到设计视图中的页面上来完成此操作,Visual Studio 会自动为您编写标记)
<%@ Register Src="~/Controls/AutoCompleteTextBox.ascx"
TagName="AutoCompleteTextBox" TagPrefix="bgs" %>
然后,当您希望 TextBox
出现在以下位置时
<bgs:AutoCompleteTextBox ID="txtAutoComplete" runat="server" Width="300px" />
最后,只需在代码中的任何位置设置控件的.Items
属性即可设置框的自动完成下拉列表内容,其余部分都将正常工作,这要归功于 zichun 的 JavaScript
Me.txtAutoComplete.Items = New String() {"Apple", "Orange", "Banana"}
已知问题
我注意到,最初这在 Web 服务器计算机上工作得很好,但在从远程计算机查看服务器上的应用程序时却失败了。但是,Server.MapPath("~")
返回指向c:\inetpub\wwwroot\...的链接 - 当远程连接到应用程序时,这显然会导致 JavaScript“对象必需”错误,因为远程计算机没有这样的文件——但在服务器上却工作得很好。答案是在控件的Page_Init
中稍微修复一下路径。
反馈
我很欢迎对此控件的任何反馈;尽管我不能保证能够帮助解决任何疑问。此控件对我的需求来说工作得非常好;虽然我会在可能的情况下尽力提供帮助,但我目前非常忙!
谢谢
我已经说了很多次了,但没有 zychun 的 JavaScript 和文章,这个控件就不可能写出来,在此。