使用和开发 AutoSuggest ASP.NET 服务器控件库

分享于 

79分钟阅读

Web开发

  繁體

AutoSuggestTextBox in action.

目录

简介

自动 AutoSuggest ASP.NET 服务器控件库提供了在 ASP.NET 页中使用自动建议文本框或者下拉 List的功能。 通过 inline 项或者数据源属性的AutoSuggestTextBox 项可以填充控件,或者使用AJAX从单独的页中检索项。 为了简化AJAX检索,提供了 AutoSuggestListPage

使用提供给你的网站中的模板和配置你的任何其他 ListControl,在 AutoSuggestListPage 中输出列表项就像向你的网站添加新项一样简单。 使用控件的AJAX功能的另一个优点是能够根据它的他控件。字段。等等 和 Parameters 属性动态填充项。

本文的目的是尽可能全面,以涵盖这里控件的各个方面。 因这里,这篇文章可以能有点太长,无法在一个坐标中进行。 把这看作是一个三部分的文章是有帮助的。 除了常规介绍,background,兴趣点 和历史部分之外,将描述的below 描述为三个单独部分可能会更容易:

  • 这个部分提供了针对如何使用库以及示例项目中代码示例的分类任务分解。
  • web服务提供程序提供的每个类库和属性都提供了一个MSDN样式快速引用,并显示了这些库与属性之间的关联关系。
  • 这部分提供了一个详细的了解库的控制是什么,它们是怎样开发的。

可以看到,描述的每个部分都被进一步分解为可以导航到使用内容的文章的中的小节。 为了提供方便,所有对在本文中使用的属性的引用都将从参考部分中显示它们的描述。 我希望你喜欢这篇文章,并且找到库有用,如果你愿意,请确定投票。 我没有把时间放在文章和代码上,因为我不认为它能够获得最好的月份。

同样,我希望你能在我自己的网站上找到更高的流量,所以我希望你能在我的网站上找到更高的流量和功能,让我尽量做到最好。 我一定会让这里的每一个人都知道,当大型项目启动时,一定要检查一下时间。

background

使用自动建议 ASP.NET 服务器控件库的JavaScript在这里是它的根目录。 代码首先在CodeProject上由zichun发布,文章在这里是 [ ^ ]。 最初作者放弃支持代码时,Dmitry Khudorozhkov采用它,改进它,并在本文的第2 部分中努力支持它。

然后,我来了想要更多。 具体来说,ASP.NET 服务器控件。 在花了几天的时间在服务器控件中包装JavaScript的现有功能之后,我仍然不满意。 我希望能够使用AJAX调用的QueryString 发送单独的控件值,并为JavaScript和server控件添加一个 for。 我完成了对原始JavaScript的非常小的更改,希望保持代码的of支持优势。

然后我就贪婪了。 我对控件和AJAX输出页面的直观和响应非常深刻,我决定放弃当前的实现来填充 DropDownList的通过 Web服务的。 在drop下拉列表中,我考虑创建全新的服务器控件和JavaScript对象,但是最终使用 butchering,修改原始JavaScript并提供在文本框和下拉列表功能之间进行切换的属性。

使用代码的

本节通过特征方法描述如何在web应用程序中使用 AutoSuggest ASP.NET 服务器控件库。 为了防止引导过长,有些特性被简短地解释,并且有关于它们的属性,没有任何解释。 请记住,你可以通过将鼠标指针悬停在文章中的任何地方,从而查看库中实现的任何属性摘要。

设置AutoSuggestTextBox脚本和图像路径。

AutoSuggestTextBox的脚本和图像路径可以通过属性网格中"文件"类别下显示的属性自定义。 属性名称和描述对于每个文件的用途都是自解释的。 这些文件的默认值位于站点的root,但如果希望将脚本和图像保留在站点的它的他目录中。

设置AutoSuggestTextBox外观

AutoSuggestTextBox的外观可以通过属性网格中"外观"类别下显示的属性定制。 考虑到控件的性质,控件的两个组件可以为它的设置外观: 文本框和建议列表。

文本框外观错误

控件文本框的外观由继承的继承 WebControl 类( 除了我自己添加的Text 属性之外)的"外观"和"版式"属性确定,这些属性为: BackColorBorderColorBorderStyleBorderWidthCssClassFontForeColorHeightWidth 属性。 必须注意,如果你决定自定义控件的高度或者字体大小,应该相应地修改下拉图像。

建议 List 外观。

控件的建议 List的外观由控件的自定义"外观"属性决定: ArrowBackColorItemBackColorItemFontNamesItemFontSizeItemForeColorSelectedItemBackColorSelectedItemForeColorUseScroll 属性。 这些属性大部分是自解释的;但是,UseScroll 属性deserves解释是否使用了一个典型的滚动条,因为它决定了建议 List 是否在顶部导航,或者使用了箭头图像来导航。

设置AutoSuggestTextBox行为

AutoSuggestTextBox的"行为"属性有些广泛,所以我将把它们分解为下一步,帮助将它们放入上下文中。

常规设置

AutoSuggestTextBox 使用 EnabledEnableThemingEnableViewStateToolTipVisible 属性继承自 WebControl。 控件的大多数常规设置仅适用于文本框模式,这些模式为: LimitStartMatchFirstNoDefaultResponseTimeResponseTimeRestrictTypingStartCheckTimeOutUseIFrameUseMouse

在文本框模式中,AutoSuggestTextBox 允许通过使用 MultiSelectDelimiter1MultiSelectDelimiter2 属性从建议 List 中选择多个选项。 这些属性的默认值分别为";"和","。 若要在文本框模式下禁用多个选择,请将这两个属性都设置为空字符串。

客户端脚本

AutoSuggestTextBox 具有执行 ClientSelectedItemCallback 属性的客户端脚本集。 要使用这个属性,将文本设置为JavaScript函数,当用户从控件 List的建议中选择条目时它将执行。 属性的默认值提供了控件预期的示例函数和参数,如下所示:

function(index, control)
{
 /*alert('Selected key:"' + control.keywords[index]
 + '" with value:"' + control.values[index] + '"');*/}

由于函数内的代码被注释掉,如果属性保留为默认值,则不会执行任何代码。 不是误导你,实际的默认值是相同的代码,但在一行上。 属性的MultilineStringEditor允许你编写多个行函数,它们仍然会执行。 若要给出公平警告,指定的函数中的语法错误将使控件无法运行。

文本框和下拉模式按钮

在文本框和下拉模式之间可以进行处理,或者可以对每个模式的某些行为进行优化和 MATCH 处理。 尽管有一些属性控制不同的行为,但是两个极端之间的切换简单,如设置 UseDropDownButton 属性。 更改这里属性将自动更改 FillVisibleFilterSuggestionsReadOnly 属性( ( 参见本文的 AutoSuggestTextBox 参考部分,以了解这些属性的每一个'目的)。 如果选择混合和 MATCH 行为,请先设置 UseDropDownButton 属性以避免 Having的链接属性重置。

填充建议列表

List的AutoSuggestTextBox 建议与 ASP.NET的List 控件的构建方式相同。 每种填充建议 List的方法都被描述为 below,并且适用于 inline 和 AJAX List,在方法描述之后详细描述。

手动 List 填充

提供建议来填充 List的AutoSuggestTextBox 或者 AutoSuggestListPage 建议建议的最简单方法是手动填充 Items 属性。 可以通过从属性网格调用ListItemCollectionEditor或者从下面示例项目中的示例项目中的源来完成设计模式:

<cc1:AutoSuggestTextBoxID="astAnimalType"runat="server"FillVisibile="False"FilterSuggestions="False"ReadOnly="True"SelectedValue=""UseDropDownButton="True"Width="200px"><Items><asp:ListItem>All</asp:ListItem><asp:ListItem>Amphibian</asp:ListItem><asp:ListItem>Bird</asp:ListItem><asp:ListItem>Fish</asp:ListItem><asp:ListItem>Invertebrate</asp:ListItem><asp:ListItem>Mammal</asp:ListItem><asp:ListItem>Reptile</asp:ListItem></Items></cc1:AutoSuggestTextBox>
数据绑定填充

对于数据绑定,AutoSuggestListBase 类公开了 DataMemberDataSourceDataSourceIDDataTextFieldDataTextFormatStringDataValueField 属性。 这些属性与任何其他 ASP.NET List 控件的用途相同。 通常,通过添加配置为检索表的DataSource 控件,然后将控件的AutoSuggestDataSourceID 设置为它的标识,然后选择要用于 DataTextFieldDataValueField 属性的字段名称,可以完成建议列表绑定。

编程 List

可以从以下示例项目的AnimalListPage 示例中演示的示例中,从页面后面的代码中填充 AutoSuggestListBase 类'Items 属性:

publicpartialclass AnimalListPage : AutoSuggestListPage
{
 private string[] amphibians = new string[] { "Frog", "Newt"/*...*/ };
 private string[] birds = new string[] { "Blue Heron", "Cardinal"/*...*/ };
 private string[] fish = new string[] { "Albacore", "Anchovy"/*...*/ };
 private string[] invertebrate = new string[] { "Ant", "Aphid"/*...*/ };
 private string[] mammals = new string[] { "Aardvark", "Addax"/*...*/ };
 private string[] reptiles = new string[] { "Agamid", "Alligator"/*...*/ };
 privatevoid Page_Load(object sender, EventArgs e)
 {
 switch (this.Request.QueryString["type"])
 {
 case"All":
 ArrayList animals = new ArrayList();
 foreach (string animal inthis.amphibians)
 animals.Add(animal);
 foreach (string animal inthis.birds)
 animals.Add(animal);
 foreach (string animal inthis.fish)
 animals.Add(animal);
 foreach (string animal inthis.invertebrate)
 animals.Add(animal);
 foreach (string animal inthis.mammals)
 animals.Add(animal);
 foreach (string animal inthis.reptiles)
 animals.Add(animal);
 animals.Sort();
 foreach (string animal in animals)
 this.AutoSuggestList.Items.Add(animal);
 break;
 case"Amphibian":
 foreach (string animal inthis.amphibians)
 this.AutoSuggestList.Items.Add(animal);
 break;
 case"Bird":
 foreach (string animal inthis.birds)
 this.AutoSuggestList.Items.Add(animal);
 break;
 case"Fish":
 foreach (string animal inthis.fish)
 this.AutoSuggestList.Items.Add(animal);
 break;
 case"Invertebrate":
 foreach (string animal inthis.invertebrate)
 this.AutoSuggestList.Items.Add(animal);
 break;
 case"Mammal":
 foreach (string animal inthis.mammals)
 this.AutoSuggestList.Items.Add(animal);
 break;
 case"Reptile":
 foreach (string animal inthis.reptiles)
 this.AutoSuggestList.Items.Add(animal);
 break;
 }
 }
}
AJAX List

在前面的"填充建议列表"部分中有两个示例项目中的代码示例。 第一个示例是在下拉模式下手动填充的AutoSuggestTextBox。 第二个示例是 AutoSuggestListPage的代码,它的AutoSuggestList 控件的Items 属性根据查询字符串的"类型"参数的值编写。

这并不符合 案例 of switch 第二个示例中的语句对应于第一个代码示例中。 代码示例 below 来自于与第一个代码示例位于同一页上的文本框模式中的AutoSuggestTextBox 控件:

<cc1:AutoSuggestTextBoxID="astAnimal"runat="server"Width="200px"AjaxUrl="~/AnimalListPage.aspx"FullRefresh="True"MatchFirst="True"NoDefault="False"><Parameters><asp:ControlParameterControlID="astAnimalType"Name="type"PropertyName="SelectedValue"/></Parameters></cc1:AutoSuggestTextBox>

示例 上面 使用AJAX填充它的建议 List。 使用 AjaxUrl 属性指定的页已经使用示例中包含的项模板添加到示例项目中。 使用项模板时,只需将模板文件的压缩压缩到适当的Visual Studio 模板目录( 我的DocumentsVisual Studio 2008 TemplatesItemTemplatesVisual C#。)。 iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 FullRefresh 设置为 true的属性确保每次显示时刷新控件 List的建议,因为随 QueryString 参数发送的值可以能已经更改。

iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 参数 属性的属性包含一个 ControlParameter 设置为 AutoSuggestTextBox 从第一个代码示例中的第一个代码示例和第二个代码示例中的NAME"类型"。 添加这里参数是通过调用 参数 设置属性,从而在设计模式中添加参数。选择 ConrolParameter 类型并从编辑器提供的下拉列表中选择控件的链接 ID。

必须注意,ConrolParameterPropertyName 属性将被忽略。 这是通过设计来防止 postback 在页面上使用 AutoSuggestTextBox的每次链接值更改时都要求使用该服务器。 ,ConrolParameterFormParameter 参数expect输入ID的输入元素并在客户机端获取可能修改的值,并在显示建议列表时与查询字符串一起发送。 参数类型的其余部分在包含 AutoSuggestTextBox 加载的页时在服务器端显式设置它们的值。

AutoSuggest ASP.NET 服务器控件库引用

自动AutoSuggest命名空间

AutoSuggest ASP.NET 服务器控件库由以下四个类组成:

  • AutoSuggestListBase - 带有AJAX输出属性的数据绑定 List的基控件。
  • AutoSuggestList - 在设计器中配置 AutoSuggestListPage的控件。
  • AutoSuggestListPage - autosuggest控件输出列表的基页。 需要使用 AutoSuggestList ( 包含在模板中)的ID添加带有 AutoSuggestList 控件的链接ASPX文件。
  • AutoSuggestTextBox - TextBox 控件,当用户键入时自动建议匹配项。

AutoSuggestListBase

AutoSuggestListBase 类从 DataBoundControl 继承,为 AutoSuggestTextBoxAutoSuggestListPage 类提供数据绑定和配置AJAX输出定界的常见功能。

数据属性
  • DataMember - 获取或者设置用于绑定的table 或者视图。
  • DataSourceID - 获取或者设置将用作数据源的IDataSource的控件 ID。
  • DataTextField - 获取或者设置数据源中提供项文本的字段。
  • DataTextFormatString - 获取或者设置应用于文本字段的格式设置。 例如 {0:d}.
  • DataValueField - 获取或者设置数据源中提供项值的字段。
  • Items - 获取列表中的项的Collection。
AJAX输出属性
  • ItemDelimiter - 获取或者设置用于分隔AJAX输出中的项的字符。
  • TextValueDelimiter - 获取或者设置用于分隔AJAX输出中的文本和值的字符。
AutoSuggestList

AutoSuggestList 继承自 AutoSuggestListBase,用作控件,以在设计器中配置 AutoSuggestListPage。 不相关的控件继承属性被自动隐藏,AutoSuggestListPage 使用该控件忽略了HTML输出。

AutoSuggestListPage

AutoSuggestListPage 类继承自 Page 类,以输出通过它的AutoSuggestList 控件( 或者直接通过'属性配置的List 项,或者通过以下代码的Page_Load 方法填充。

AutoSuggestTextBox

AutoSuggestTextBox 类继承自 AutoSuggestListBase,并实现 IPostBackDataHandler 以提供组合文本框/下拉 List 控件。 在文本框模式中,控件允许输入并根据用户通过 Items 属性提供的项自动显示匹配建议,可以使用数据绑定,或者通过AJAX调用提供它的项。 下拉模式下,控件是只读的,通过单击可以自定义控件下拉按钮的方式展开未过滤的建议,可以将它的文本更改为文本框模式。

AJAX输出属性
  • AjaxUrl - 获取或者设置要从中检索建议的URL。
  • FullRefresh - 获取或者设置一个值,该值指示脚本是否应在每个类型字符之后发送AJAX请求。
  • Parameters 获取或者设置要传递给AJAX页面 QueryString的参数。
外观属性
  • ArrowBackColor - 获取或者设置箭头行( 如果 UseScroll 为 false 则使用)的background 颜色。
  • ItemBackColor - 获取或者设置建议列表的background 颜色。
  • ItemFontNames - 获取或者设置建议项的字体。
  • ItemFontSize - 获取或者设置建议项的字体大小。
  • ItemForeColor - 获取或者设置非选定建议的文本颜色。
  • SelectedItemBackColor - 获取或者设置建议列表中选定项的background 颜色。
  • SelectedItemForeColor - 获取或者设置选定建议的文本颜色。
  • Text - 获取或者设置控件的文本值。
  • UseScroll - 获取或者设置一个值,该值指示控件是否应使用滚动条( true ) 或者向上/向下箭头按钮( false )。
行为属性
  • ClientItemSelectedCallback 获取或者设置当用户从建议列表中选择项时执行的客户端JavaScript回调函数。
  • EntryLimit - 获取或者设置自动完成将在一段时间内显示的项的数目。
  • FillVisible - 获取或者设置一个值,该值指示脚本填充列表时是否可以见建议 List。
  • FilterSuggestions - 获取或者设置一个值,该值指示是否根据值输入筛选建议。
  • LimitStart - 获取或者设置一个值,该值指示是否应将自动完成程序限制为关键字的开头。
  • MatchFirst - 获取或者设置一个值,该值指示如果 LimitStart 为 false,则是否应首先显示精确的MATCHES。
  • MultiSelectDelimiter1 - 获取或者设置多个自动完成项的第一个分隔符。 将两者设置为空白后自动完成。
  • MultiSelectDelimiter2 - 获取或者设置多个自动完成项的第二个分隔符。 将两者设置为空白后自动完成。
  • NoDefault - 获取或者设置一个值,该值指示控件是否应省略选择建议列表中的第一项。
  • ReadOnly - 获取或者设置一个值,该值指示文本输入是否只读,但仍允许建议选择。 如果这里属性设置为 true,则建议在页面加载时自动填充,或者如果指定的控件有它的值。
  • ResponseTime - 获取或者设置最后一个字符类型与实际查询之间的时间( 以毫秒为单位)。
  • RestrictTyping - 获取或者设置一个值,该值指示控件是否应限制为 array的现有成员。
  • StartCheck - 获取或者设置在建议显示为(。> 1有效) 之前需要键入的字符数。
  • TimeOut - 获取或者设置自动完成超时,以毫秒为单位( 0: 自动完成从不超时)。
  • UseIFrame - 获取或者设置一个值,该值指示控件是否应使用IFrame元素修复建议 List 定位( 仅 IE )。
  • UseDropDownButton - 获取或者设置一个值,该值指示控件是否应显示下拉按钮。 更改这里属性将自动更改控件的FillVisibleFilterSuggestionsReadOnly 属性,以便将它的与下拉 List 或者文本框一起运行。
  • UseMouse - 获取或者设置一个值,该值指示是否应该启用控件的鼠标支持。
文件属性
  • DownHoverImagePath 获取或者设置控件使用的向下箭头悬停图像文件的路径。
  • DownImagePath - 获取或者设置控件使用的向下箭头图像文件的路径。
  • ScriptPath - 获取或者设置控件使用的autosuggest JavaScript文件的路径。
  • UpHoverImagePath 获取或者设置控件使用的向上箭头悬停图像文件的路径。
  • UpImagePath - 获取或者设置控件使用的向上箭头图像文件的路径。
动作事件
  • SelectedIndexChanged - 当 SelectedIndex 属性更改时激发。
  • SelectedTextChanged - 当 SelectedText 属性更改时激发。
  • SelectedValueChanged - 当 SelectedValue 属性更改时激发。
  • TextChanged - 当 Text 属性更改时激发。

是如何工作的。

在本节中,我将讨论开发自动建议 ASP.NET 服务器控件库所需的内容。 Having 在过去开发了很多 Windows 控件,我已经对. NET 组件开发有了很好的理解。 为一个to文章开发这个库是我确保我能够为自己开发 ASP.NET 服务器控件的方式。

是否要学习如何为初学者开发 ASP.NET 服务器控件,或者你只是想知道我是如何实现的。 如上所述,这是一个学习经验,所以如果你是一个寻找我的代码并指出我做了错误或者可能做得更好的every,请这么做吧。

这说明库的目标是实现功能性需求 below,然后我将详细介绍它们在执行过程中的实现方式。

  • 输出文本输入 - 覆盖如何将HTML文本输入输出到页面的方法。
  • 使用 ViewState - 覆盖 AutoSuggestTextBox '的s 在回发之间保持。
  • 实现 IPostBackDataHandler - 涵盖了 AutoSuggestTextBox 通知它的文本已经在客户端上修改并反映了 postback 在服务器上的更改。
  • 数据绑定ListControl行为 Covers Covers类如何提供属性并实现方法来绑定数据库 项目 属性到数据源。
  • 自动生成JavaScript类 - 简要介绍支持建议 List的JavaScript源代码,并详细说明扩展代码以扩展由Zichun和Dmitry开发的代码,以支持 AutoSuggestTextBox的功能。
  • 输出自动AutoSuggest脚本调用- Covers Covers AutoSuggest对象如何被实例化,以及它的属性设置为基于 AutoSuggestTextBox 中实现的属性的属性。
  • 设计器功能 Covers涵盖了如何在设计模式中实现从属性网格配置控件的所有 bells。
  • 脚本注册 Covers Covers Covers如何注册 autosuggest JavaScript,以及获取调用脚本以在 ASP.NET AJAX UpdatePanel 中函数的额外方法。
  • 用于AJAX输出的 AutoSuggestListPage - 介绍如何创建AJAX列表的基本页面,以及如何使用控件的实例进行配置和功能的操作。
  • 用于的项目模板- 覆盖如何创建项模板以简化使用新项目对话框向web项目添加 AutoSuggestListPage

输出文本输入

其他服务器控件一样,这个库的主要目的是接受用户输入,以便可以在服务器上检索和使用它。 为了实现这个目的,AutoSuggestTextBox 通过继承 WebControl 并重写它的RenderContents 方法来向页面写入一个HTML文本类型输入元素。 代码 below 显示控件如何输出控件从 WebControl 继承的属性的文本输入和帐户。

protectedoverridevoid RenderContents(HtmlTextWriter output)
{
 if (this.Visible)
 {
 output.WriteBeginTag("input");
 output.WriteAttribute("type", "text");
 output.WriteAttribute("value", this.Text);
 output.WriteAttribute("autocomplete", "off");
 output.WriteAttribute("id", this.ClientID);
 output.WriteAttribute("name", this.UniqueID);
 if (!this.Enabled)
 output.WriteAttribute("disabled", "disabled");
 if (this.CssClass!= string.Empty)
 output.WriteAttribute("class", this.CssClass);
 if (this.ToolTip!= string.Empty)
 output.WriteAttribute("title", this.ToolTip);
 output.Write(" style="");
 if (this.Width!= Unit.Empty)
 output.WriteStyleAttribute("width", this.Width.ToString());
 if (this.Height!= Unit.Empty)
 output.WriteStyleAttribute("height", this.Height.ToString());
 if (this.Font.Name!= string.Empty)
 output.WriteStyleAttribute("font-family", this.Font.Name);
 if (this.Font.Size!= FontUnit.Empty)
 output.WriteStyleAttribute("font-size", this.Font.Size.ToString());
 if (this.BackColor!= Color.Empty)
 output.WriteStyleAttribute("background-color", ColorTranslator.ToHtml(this.BackColor));
 if (this.ForeColor!= Color.Empty)
 output.WriteStyleAttribute("color", ColorTranslator.ToHtml(this.ForeColor));
 if (this.BorderColor!= Color.Empty)
 output.WriteStyleAttribute("border-color", ColorTranslator.ToHtml(this.BorderColor));
 if (this.BorderStyle!= BorderStyle.NotSet)
 output.WriteStyleAttribute("border-style", this.BorderStyle.ToString());
 if (this.BorderWidth!= Unit.Empty)
 output.WriteStyleAttribute("border-width", this.BorderWidth.ToString());
 output.WriteLine(""/>");
 }
}

如你在示例中所看到的,控件做的第一件事是检查它的Visible 属性是否为 true ;否则,将不向页面写入。 如果可以见,控件使用与方法参数输出传递的HtmlTextWriter 对象调用它的WriteBeginTag 方法来打开带有"输入"标记 NAME的元素。 然后,WriteAttribute 方法将类型属性设置为"文本",值设置为控件的Text 属性值,以防止浏览器显示自己的完整完整建议。

接下来,id和 NAME 属性写入到从 WebControl 继承的ClientIDUniqueID 属性的元素集中。 这些属性的值是输出而不是这些属性的ID 属性值,以确保值在页的上下文中是唯一的。

然后,如果 EnabledCssClassToolTip 属性的各个值都要求从 WebControl 设置继承,则代码将添加禁用的。类和标题属性。

添加到元素的最后一个属性是样式属性。 这是通过使用 Write 方法来添加样式属性的,然后使用 WriteStyleAttribute 方法来添加从 WebControl 继承的每个"外观"和"版式"属性。 finally,将添加样式属性的结束引号,并且输入标记与 WriteLine 方法关闭。

使用 ViewState

ASP.NET 提供了将控件状态与基础 ControlViewState 属性之间的控件状态保存的能力。 ViewState 属性是一个字典,它的值在页面上的隐藏字段中编码。 示例代码 below 用于 AutoSuggestTextBox ''s 文本 使用ViewState在后端之间保持它的值的属性。

publicstring Text
{
 get {
 if (this.EnableViewState)
 {
 if (this.ViewState["Text"]!= null)
 returnthis.ViewState["Text"].ToString();
 elsereturnstring.Empty;
 }
 elsereturnthis.myText;
 }
 set {
 if (this.EnableViewState)
 this.ViewState["Text"] = value;
 elsethis.myText = value;
 }
}

在这里属性中,在使用 ViewStateDictionary 之前检查 EnableViewState 属性。 这是因为控件不需要特别的防止,以防止在 ViewState 设置为 false 时将 EnableViewState 字段写入到。 如果 EnableViewState 是 true,通过只引用为属性定义的键来设置和检索值,否则将使用在类中声明的private 字段来返回属性值。

实现 IPostBackDataHandler

为了允许客户端修改的HTML文本输入的值被反映在 文本 属性 AutoSuggestTextBox 控件实现 IPostBackDataHandler 接口。 为了实现 IPostBackDataHandler 接口,控件需要实现 LoadPostDataRaisePostDataChangedEvent 方法,如下面的示例代码所示。

#region IPostBackDataHandler Membersprivatebool myTextChanged;privatebool mySelectedTextChanged;privatebool mySelectedValueChanged;privatebool mySelectedIndexChanged;publicbool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
 if (postCollection[this.UniqueID]!= this.Text)
 {
 this.Text = postCollection[this.UniqueID];
 this.myTextChanged = true;
 }
 if (postCollection[this.UniqueID + "$SelectedText"]!= this.SelectedText)
 {
 this.SelectedText = postCollection[this.UniqueID + "$SelectedText"];
 this.mySelectedTextChanged = true;
 }
 if (postCollection[this.UniqueID + "$SelectedValue"]!= this.SelectedValue)
 {
 this.SelectedValue = postCollection[this.UniqueID + "$SelectedValue"];
 this.mySelectedValueChanged = true;
 }
 if (postCollection[this.UniqueID + "$SelectedIndex"]
!= this.SelectedIndex.ToString())
 {
 this.SelectedIndex = Convert.ToInt32(postCollection[this.UniqueID
 + "$SelectedIndex"]);
 this.mySelectedIndexChanged = true;
 }
 return (this.myTextChanged || this.mySelectedIndexChanged
 || this.mySelectedTextChanged || this.mySelectedValueChanged);
}publicvoid RaisePostDataChangedEvent()
{
 if (this.myTextChanged)
 this.OnTextChanged(new EventArgs());
 if (this.mySelectedTextChanged)
 this.OnSelectedTextChanged(new EventArgs());
 if (this.mySelectedValueChanged)
 this.OnSelectedValueChanged(new EventArgs());
 if (this.mySelectedIndexChanged)
 this.OnSelectedIndexChanged(new EventArgs());
}#endregion

从这个示例中可以看到,实际上有4 个属性链接到post数据。 由于 LoadPostData 方法只返回一个布尔值来指示是否调用了 RaisePostDataChangedEvent 方法,因这里声明了四个 private 字段来存储。

LoadPostData 方法中,值的值 文本 根据 postCollection 参数中索引属性 UniqueID的值对属性进行检查的值。 回想一下前一节,你会记得控件属性的UniqueID 被用来确定HTML文本输入的NAME。 这说明 postCollection 包含在提交表单时发送回发送到服务器的每个表单域值的每个表单字段值。 如果 postCollection 中包含的值确实不同于属性的值,则将该属性设置为修改的值,并将 myTextChanged 值设置为 true。

以相同的方式检查其他三个链接的数据链接属性的方式与 文本UniqueID 方法在 Render 方法中注册隐藏字段时,控件属性的的连接方式相同,如脚本注册部分所示。 处理每个post数据链接属性后,如果任何属性值已经更改,则 LoadPostData 方法返回 true。

如果 LoadPostData 方法返回 true,则执行 RaisePostDataChanged 方法。 inside 方法,每个存储属性的private 字段都是否被检查,并且触发适当事件的方法被调用。 事件触发方法并没有很多,但是如果你好奇,请参见下面包含 TextChanged 事件代码及其触发方法的例子。

protectedvoid OnTextChanged(EventArgs e)
{
 if (this.TextChanged!= null)
 this.TextChanged(this, e);
}
[Category("Action")]
[Description("Fires when the Text property has been changed.")]publicevent EventHandler TextChanged;

数据绑定ListControl行为

数据绑定是在 AutoSuggestListBase 类。由于这里类是由 AutoSuggestTextBox 还有 AutoSuggestList 控件使用的控件 AutoSuggestListPage 不需要所有的ListControl 功能。 相反, AutoSuggestListBase 从 DataBoundControl 继承并实现自己 项目 和"数据"属性,并通过重写 PerformDataBinding 方法执行自己的数据绑定,如下面的示例代码所示。

protectedoverridevoid PerformDataBinding(IEnumerable dataSource)
{
 if (dataSource!= null &&!this.DesignMode)
 {
 object text;
 objectvalue;
 foreach (object row in dataSource)
 {
 text = null;
 value = null;
 if (this.DataTextField!= string.Empty
 && this.DataTextFormatString!= string.Empty)
 text = DataBinder.GetPropertyValue(row, this.DataTextField
, this.DataTextFormatString);
 elseif (this.DataTextField!= string.Empty)
 text = DataBinder.GetPropertyValue(row, this.DataTextField);
 if (this.DataValueField!= string.Empty)
 value = DataBinder.GetPropertyValue(row, this.DataValueField);
 if (text!= null)
 {
 if (value!= null)
 this.Items.Add(new ListItem(text.ToString(), value.ToString()));
 elsethis.Items.Add(new ListItem(text.ToString()));
 }
 }
 }
}

在这里方法中,DataSource 参数实现 IEnumerable 类。 确保 DataSource 不在 控件不处于设计模式,则声明两个对象以临时存储来自 DataSource的每个行的文本和值字段。 iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 foreach 语句从 DataSource 中循环遍历每一行。 使用 GetPropertyValue 方法的DataBinder static 根据每个行对象的值来获取每个行对象的值。 数据文本字段 , DataTextFormatString 以及 数据值字段 一旦从 DataSource 中检索到值,它们将被添加到该控件的ListItemCollection 中。 项目 使用临时对象的ToString 方法确保在下一次迭代中不将值设置为 null。

AutoSuggest JavaScript JavaScript

到目前为止我们所讨论的只是 AutoSuggestTextBox 实现与 TextBox 相同的行为,注册几个隐藏字段,以及如何为 ListControl 行为设置基础。 显然,建议 List 和下拉 List 行为不只是神奇地发生在它们自己的。 所有这些都是通过autosuggest类在客户机端处理的。

但是,对于本文而言,JavaScript如何工作将是非常神奇的。 相反,我将提醒你原始文章源自( 复制并粘贴到 background 节),并简要介绍我所做的更改。 代码首先由zichun发布到 CodeProject,文章在这里是 [ ^ ]。 最初作者放弃支持代码时,Dmitry Khudorozhkov采用它,改进它,并在本文的第2 部分中努力支持它。

Basically JavaScript类 exposes AutoSuggestTextBoxClientItemSelectedCallbackAjaxUrl 属性的几乎所有自定义属性的属性,Items。和属性都通过counstructor代码传递。 为了满足 AutoSuggestTextBox的下降模式和AJAX参数要求,将控件。FillVisibleFilterSuggestionsReadOnlyUseDropDownButton 属性的Parameters 添加到了JavaScript类。 JavaScript类中的所有属性都使用了一个全部 lowercase。下划线间隔命名约定,服务器控件上的一些属性名完全改变以满足传统的。 NET命名约定。

输出自动AutoSuggest脚本调用

autosuggest类设计成面向对象的方式,这大大简化了对初始化控件的功能所需的JavaScript代码的输出。 正如代码 below 中所示,该过程编写JavaScript以创建新的in对象并将它的属性设置为 AutoSuggestTextBox 中的等价属性。

protectedvoid RenderScript(HtmlTextWriter output)
{
 if (this.Visible)
 {
 // Checking if the Items property's text and value properties differ// to determine if both values need to be set for each JavaScript Array// item needs to store both values.bool multiValue = false;
 foreach (ListItem item inthis.Items)
 {
 multiValue = (item.Text!= item.Value);
 if (multiValue)
 break;
 }
 // Opening script tag. output.WriteBeginTag("script");
 output.WriteAttribute("type", "text/javascript");
 output.WriteLine(">");
 // Declaring and instantiating the suggestion array if no AJAX// URL specified.if (this.Items.Count >0 && this.AjaxUrl == string.Empty)
 {
 output.Write("var" + this.ClientID + "Items = [");
 if (multiValue)
 {
 for (int itemIndex = 0; itemIndex <this.Items.Count; itemIndex++)
 {
 if (itemIndex == 0)
 output.WriteLine("['" + this.Items[itemIndex].Text.Replace("'", "'")
 + "', '" + this.Items[itemIndex].Value.Replace("'", "'")
 + "']");
 elseif (itemIndex!= this.Items.Count - 1)
 output.WriteLine(", ['" + this.Items[itemIndex].Text.Replace("'", "'") + "', '" + this.Items[itemIndex].Value.Replace("'", "'")
 + "']");
 else output.Write(", ['" + this.Items[itemIndex].Text.Replace("'", "'")
 + "', '" + this.Items[itemIndex].Value.Replace("'", "'")
 + "']");
 }
 }
 else {
 for (int itemIndex = 0; itemIndex <this.Items.Count; itemIndex++)
 {
 if (itemIndex == 0)
 output.WriteLine("'" + this.Items[itemIndex].Text.Replace("'", "'") + "'");
 elseif (itemIndex!= this.Items.Count - 1)
 output.WriteLine(", '" + this.Items[itemIndex].Text.Replace("'", "'") + "'");
 else output.Write(", '" + this.Items[itemIndex].Text.Replace("'", "'") + "'");
 }
 }
 output.WriteLine("];");
 }
 // Declaring and instantiating the autosuggest object.if (this.AjaxUrl == string.Empty)
 output.WriteLine("var" + this.ClientID
 + "AutoSuggest = new autosuggest('" + this.ClientID + "'," + this.ClientID + "Items, null," + this.ClientItemSelectedCallback
 + ");");
 else output.WriteLine("var" + this.ClientID
 + "AutoSuggest = new autosuggest('" + this.ClientID + "', '', '" + ResolveUrl(this.AjaxUrl) + "?'," + this.ClientItemSelectedCallback
 + ");");
 // Setting the autosuggest object properties.if (this.TextValueDelimiter!= ",")
 output.WriteLine(this.ClientID + "AutoSuggest.item_delimiter = '" + this.TextValueDelimiter + "';");
 if (this.ItemDelimiter!= "|")
 output.WriteLine(this.ClientID + "AutoSuggest.ajax_delimiter = '" + this.ItemDelimiter + "';");
 if (this.MultiSelectDelimiter1!= ";" && this.MultiSelectDelimiter2!= "," && this.MultiSelectDelimiter1!= string.Empty)
 {
 output.WriteLine(this.ClientID + "AutoSuggest.text_delimiter = ['" + this.MultiSelectDelimiter1 + "', '" + this.MultiSelectDelimiter2
 + "'];");
 }
 if (!this.ItemBackColor.Equals(Color.FromArgb(255, 255, 240)))
 output.WriteLine(this.ClientID + "AutoSuggest.bg_color = '" + ColorTranslator.ToHtml(this.ItemBackColor) + "';");
 if (!this.ArrowBackColor.Equals(Color.FromArgb(101, 98, 145)))
 output.WriteLine(this.ClientID + "AutoSuggest.ar_color = '" + ColorTranslator.ToHtml(this.ArrowBackColor) + "';");
 if (!this.ItemForeColor.Equals(Color.Black))
 output.WriteLine(this.ClientID + "AutoSuggest.text_color = '" + ColorTranslator.ToHtml(this.ItemForeColor) + "';");
 if (!this.SelectedItemForeColor.Equals(Color.FromArgb(240, 0, 0)))
 output.WriteLine(this.ClientID + "AutoSuggest.htext_color = '" + ColorTranslator.ToHtml(this.SelectedItemForeColor) + "';");
 if (!this.SelectedItemBackColor.Equals(Color.FromArgb(214, 215, 231)))
 output.WriteLine(this.ClientID + "AutoSuggest.hcolor = '" + ColorTranslator.ToHtml(this.SelectedItemBackColor) + "';");
 if (this.ItemFontNames!= "verdana,arial,helvetica")
 output.WriteLine(this.ClientID + "AutoSuggest.font = '" + this.ItemFontNames + "';");
 if (this.ItemFontSize!= Unit.Parse("10px")
 && this.ItemFontSize!= Unit.Empty)
 output.WriteLine(this.ClientID + "AutoSuggest.font_size = '" + this.ItemFontSize.ToString() + "';");
 if (this.TimeOut!= 0)
 output.WriteLine(this.ClientID + "AutoSuggest.time_out =" + this.TimeOut.ToString() + ";");
 if (this.ResponseTime!= 500)
 output.WriteLine(this.ClientID + "AutoSuggest.response_time =" + this.ResponseTime.ToString() + ";");
 if (this.EntryLimit!= 10)
 output.WriteLine(this.ClientID + "AutoSuggest.entry_limit =" + this.EntryLimit.ToString() + ";");
 if (this.StartCheck!= 0)
 output.WriteLine(this.ClientID + "AutoSuggest.start_check =" + this.StartCheck.ToString() + ";");
 if (this.StartCheck!= 0)
 output.WriteLine(this.ClientID + "AutoSuggest.start_check =" + this.StartCheck.ToString() + ";");
 if (this.LimitStart)
 output.WriteLine(this.ClientID + "AutoSuggest.limit_start = true;");
 if (this.MatchFirst)
 output.WriteLine(this.ClientID + "AutoSuggest.match_first = true;");
 if (this.RestrictTyping)
 output.WriteLine(this.ClientID + "AutoSuggest.restrict_typing = true;");
 if (this.FullRefresh)
 output.WriteLine(this.ClientID + "AutoSuggest.full_refresh = true;");
 if (!this.UseIFrame)
 output.WriteLine(this.ClientID + "AutoSuggest.use_iframe = false;");
 if (!this.UseScroll)
 output.WriteLine(this.ClientID + "AutoSuggest.use_scroll = false;");
 if (!this.UseMouse)
 output.WriteLine(this.ClientID + "AutoSuggest.use_mouse = false;");
 if (!this.NoDefault)
 output.WriteLine(this.ClientID + "AutoSuggest.no_default = false;");
 if (!this.FilterSuggestions)
 output.WriteLine(this.ClientID 
 + "AutoSuggest.filter_suggestions = false;");
 if (!this.FillVisibile)
 output.WriteLine(this.ClientID + "AutoSuggest.fill_visible = false;");
 if (this.ReadOnly)
 output.WriteLine(this.ClientID + "AutoSuggest.read_only = true;");
 if (this.UseDropDownButton)
 output.WriteLine(this.ClientID
 + "AutoSuggest.use_dropdown_button = true;");
 // Adding each parameters to the array with names and values// based on parameter type.foreach (Parameter item inthis.Parameters)
 {
 if (item is ControlParameter)
 {
 Control control = this.Parent.FindControl(
 ((ControlParameter)item).ControlID);
 if (control == null)
 {
 Control parent = this.Parent;
 while (parent!= null && control == null)
 {
 parent = parent.Parent;
 control = parent.FindControl(
 ((ControlParameter)item).ControlID);
 }
 }
 if (control!= null)
 output.WriteLine(this.ClientID + "AutoSuggest.parameters[" + this.ClientID + "AutoSuggest.parameters.length]" + " = ['@" + control.ClientID + "', '" + item.Name + "'];");
 }
 elseif (item is FormParameter)
 output.WriteLine(this.ClientID + "AutoSuggest.parameters[" + this.ClientID + "AutoSuggest.parameters.length]" + " = ['@" + ((FormParameter)item).FormField + "', '" + item.Name + "'];");
 elseif (item is QueryStringParameter)
 output.WriteLine(this.ClientID + "AutoSuggest.parameters[" + this.ClientID + "AutoSuggest.parameters.length]" + " = ['" + item.Name + "', '" + Page.Request.QueryString[
 ((QueryStringParameter)item).QueryStringField] + "'];");
 elseif (item is CookieParameter)
 output.WriteLine(this.ClientID + "AutoSuggest.parameters[" + this.ClientID + "AutoSuggest.parameters.length]" + " = ['" + item.Name + "', '" + Page.Request.Cookies[((CookieParameter)item).CookieName].Value
 + "'];");
 elseif (item is SessionParameter)
 output.WriteLine(this.ClientID + "AutoSuggest.parameters[" + this.ClientID + "AutoSuggest.parameters.length]" + " = ['" + item.Name + "', '" + Page.Session[((SessionParameter)item).SessionField].ToString()
 + "'];");
 elseif (item is ProfileParameter)
 output.WriteLine(this.ClientID + "AutoSuggest.parameters[" + this.ClientID + "AutoSuggest.parameters.length]" + " = ['" + item.Name + "', '" + HttpContext.Current.Profile[
 ((ProfileParameter)item).PropertyName].ToString() + "'];");
 else output.WriteLine(this.ClientID + "AutoSuggest.parameters[" + this.ClientID + "AutoSuggest.parameters.length]" + " = ['" + item.Name + "', '" + item.DefaultValue + "'];");
 }
 // Setting the autosuggest object image paths.if (this.DownImagePath!= "~/arrow-down.gif")
 output.WriteLine(this.ClientID + "AutoSuggest.image[0] =" + ResolveUrl(this.DownImagePath));
 if (this.DownHoverImagePath!= "~/arrow-down-d.gif")
 output.WriteLine(this.ClientID + "AutoSuggest.image[1] =" + ResolveUrl(this.DownHoverImagePath));
 if (this.UpImagePath!= "~/arrow-up.gif")
 output.WriteLine(this.ClientID + "AutoSuggest.image[2] =" + ResolveUrl(this.UpImagePath));
 if (this.UpHoverImagePath!= "~/arrow-up-d.gif")
 output.WriteLine(this.ClientID + "AutoSuggest.image[3] =" + ResolveUrl(this.UpHoverImagePath));
 if (this.DropDownImagePath!= "~/drop-down.png")
 output.WriteLine(this.ClientID + "AutoSuggest.image[4] =" + ResolveUrl(this.DropDownImagePath));
 if (this.DropDownHoverImagePath!= "~/drop-down_h.png")
 output.WriteLine(this.ClientID + "AutoSuggest.image[5] =" + ResolveUrl(this.DropDownHoverImagePath));
 if (this.DropDownPressedImagePath!= "~/drop-down_p.png")
 output.WriteLine(this.ClientID + "AutoSuggest.image[6] =" + ResolveUrl(this.DropDownPressedImagePath));
 output.Write("</script>");
 }
}

不要让方法的长度误导你;如果JavaScript类没有以对象方式实现,代码可以能更复杂。 我将让代码中的注释为你解释所有发生的事情,而不是丢失你。 explained输出参数的不同方法解释了在输出文本输入页面中写入HTML的较短示例,用于防止任何不必要的输出的属性的检查属性。

设计器功能

为了尽可以能简单地编辑 AutoSuggestTextBoxAutoSuggestListBase 属性值,控件利用了. NET 框架的许多 UITypeEditor s。 当然,可以创建自定义 UITypeEditor s,但是对于任何属性来说,这并不是必需的。 然而,对于每个任务来说,我都会在这里继续查看这些信息。

大多数属性使用 EditorAttribute 指定如何在设计模式中从属性网格编辑它们,而其他属性则需要额外的属性。 下面列出了每个 UITypeEditor 和属性。

  • ImageUrlEditor - UrlPropertyAttribute 用于允许从项目中选择一个文件作为图像的URL。 用于建议导航箭头和下拉按钮图像属性,如下面的示例所示。
  • [UrlProperty(), Editor(typeof(ImageUrlEditor), typeof(UITypeEditor))]publicstring DownHoverImagePath //...
  • UrlEditor - 用于 UrlPropertyAttribute,允许从项目中选择要用作URL的文件。 用于 ScriptPathAjaxUrl 属性,如下面的示例所示。
  • [UrlProperty(), Editor(typeof(UrlEditor), typeof(UITypeEditor))]publicstring AjaxUrl //...
  • ColorEditor - 用于允许从下拉 List 中设置命名颜色,并自定义对话框。 用于颜色"外观"属性,如下面的示例所示。
  • [Editor(typeof(ColorEditor), typeof(UITypeEditor))]publicstring ItemBackColor //...
  • 使用 TypeConverterAttribute 指定 DataFieldConverter 使用 NotifyParentPropertyAttribute 允许从使用drop属性指定的数据源中选择可用的列 NAME。 用于 DataTextFieldDataValueField 属性,如下面的示例所示。
  • [NotifyParentProperty(true), TypeConverter(typeof(DataFieldConverter))]publicstring DataTextField //...
  • PersistanceMode - 用 PersistenceModeAttribute 指定,用于设置属性是在 ASP.NET 源中设置的,还是用标记的子元素设置的。 用于 TextItems 属性,如下面的示例所示。
  • [PersistenceMode(PersistenceMode.InnerProperty)]publicstring Text //...
  • CategoryAttributeDescriptionAttribute - 用于设置属性或者事件如何在属性网格中分类和描述。 用于属性网格可以浏览的所有属性和事件,如下面的示例所示。
  • [Category("Appearance"), Description("The text value of the control.")]publicstring Text //...
  • DefaultValueAttribute - 用于指定不需要在标记( 属性值应设置为 MATCH 中指定的值'构造函数中指定的属性的默认值。 用于几乎所有的属性,例如示例 below 中设置 Color 属性的默认值。
  • [DefaultValue(typeof(Color), "0xF00000")]public Color SelectedItemForeColor //...
  • MergablePropertyAttribute - 用于指定在选择多个控件时是否可以在属性网格中编辑属性。 用于 ParametersItems 属性,如下面的示例所示。
  • [MergableProperty(false)]public ParameterCollection Parameters //...
  • BrowsableAttribute - 用于指定属性是否可以在属性网格中编辑。 用于 AutoSuggestTextBoxSelectedIndexSelectedValueSelectedText 属性和 AutoSuggestList的几个不相关属性,如下面的示例所示。
  • [Browsable(false)]publicint SelectedIndex //...

如你所见,可以从. NET 框架中提供相当多的属性和 UITypeEditor,用于为你自己的组件添加设计器支持。 这个库使用的设计工具有很多,这是框架和 System.Drawing.Design 程序集的.NET System.Design。

如果你自己的组件属性尚不能在. NET 框架中实现,那么总是有可以能开发你自己的组件属性。 可以通过从 UITypeEditor 继承自定义编辑器,设计人员可以从设计器中的可以扩展菜单中编辑组件,方法是通过从 HtmlControlDesigner 继承来创建。 在开发这个库时,添加该特性的高级设计器支持并不是真正的优先级,但是将来的更新中可能会添加。

脚本注册插件

对于 ASP.NET 2.0版本的库中的脚本注册,实际上没有很多涉及到的内容。 由于 AutoSuggestTextBox 使用 inline 脚本来初始化控件,因这里需要在 ASP.NET 3.5 AJAX UpdatePanel 中正常工作。 因此,库可以在两个不同的程序集版本中。

这两个版本中的惟一区别是 AutoSuggestTextBoxRenderOnPreRender 方法。 对于两个版本之间的可维护性,AutoSuggestTextBox 类被声明为 部分RenderOnPreRender 方法在两个项目的文件中实现,它的余的文件作为链接项添加。 使用Eeflection调用所需的ScriptManager 方法来注册 ASP.NET 2.0中的脚本,但该方法在使用库时被证明是一个破坏。

ASP.NET 2.0

如前所述,不需要完全完成 register的ASP.NET 2.0版本的脚本。 通过重写控制方法的OnPreRender 来注册 AutoSuggestTextBox 所使用的脚本文件,如下面的示例代码所示。

publicpartialclass AutoSuggestTextBox
{
 protectedoverridevoid OnPreRender(EventArgs e)
 {
 if (!Page.ClientScript.IsClientScriptBlockRegistered("autosuggest"))
 {
 string path = ResolveUrl(this.ScriptPath);
 string script = "<script type="text/javascript" src="" + path + ""></script>";
 Page.ClientScript.RegisterClientScriptBlock(typeof(Page)
, "autosuggest", script);
 }
 base.OnPreRender(e);
 }
 protectedoverridevoid Render(HtmlTextWriter writer)
 {
 RenderContents(writer);
 if (!this.DesignMode)
 {
 RenderScript(writer);
 Page.ClientScript.RegisterHiddenField(this.UniqueID + "$SelectedText", this.SelectedText);
 Page.ClientScript.RegisterHiddenField(this.UniqueID + "$SelectedValue", this.SelectedValue);
 Page.ClientScript.RegisterHiddenField(this.UniqueID + "$SelectedIndex", this.SelectedIndex.ToString());
 }
 }
}

在这里方法中,脚本文件包含使用属性的PageClientScript 注册的自动建议JavaScript类。 在注册脚本之前,一个检查确保它尚未注册。 然后将脚本文件的路径解析成脚本标记,并将它的注册为客户端脚本 block。 应该注意,我可以使用 RegisterClientScriptResource 方法,但是当异常被抛出时,在测试中不适当地设置 ScriptFile。 在后视中,这可以能是一个争议的动作,但如果你不喜欢它,你知道如何改变它。

为了比较 ASP.NET 3.5 AJAX版本,我在这个示例中包含了 Render 方法,并说明了重写 Render 方法的另一个目的。 默认情况下,WebControlRender 方法将 span 元素写入页面,该元素将to设置为 ClientID 属性的值。 由于这将创建与控件输输元素输出的of冲突,不会对基类的Render 方法进行调用。

Render 方法编写了HTML输入元素和脚本后,控件用 SelectedTextSelectedValueSelectedIndex 属性注册三个隐藏字段。 这些字段的名称被设置为控件属性concantenated的UniqueID 值,并用字符串指示它表示的属性。 is JavaScript对象确保在从建议列表中选择项时相应地设置这些字段的值。

ASP.NET 3.5 AJAX组件

就像前面提到的,如果在 ASP.NET 3.5 AJAX UpdatePanel 中使用,ScriptManager 用于对初始化控件实例的脚本文件和 inline 脚本进行初始化。 你可以通过下面的示例代码来了解这是如何实现的。

publicpartialclass AutoSuggestTextBox
{
 protectedoverridevoid OnPreRender(EventArgs e)
 {
 string path = ResolveUrl(ScriptPath);
 string script = "<script type="text/javascript" src="" + path + ""></script>";
 ScriptManager sm = ScriptManager.GetCurrent(this.Page);
 if (sm!= null && sm.IsInAsyncPostBack)
 ScriptManager.RegisterClientScriptBlock(this, typeof(AutoSuggestTextBox), "autosuggest", script, false);
 elseif (!Page.ClientScript.IsClientScriptBlockRegistered("autosuggest"))
 Page.ClientScript.RegisterClientScriptBlock(typeof(Page)
, "autosuggest", script);
 base.OnPreRender(e);
 }
 protectedoverridevoid Render(HtmlTextWriter writer)
 {
 RenderContents(writer);
 ScriptManager sm = ScriptManager.GetCurrent(this.Page);
 if (sm!= null && sm.IsInAsyncPostBack &&!this.DesignMode)
 {
 StringWriter sw = new StringWriter();
 RenderScript(new HtmlTextWriter(sw));
 string script = sw.ToString();
 ScriptManager.RegisterStartupScript(this, typeof(AutoSuggestTextBox), UniqueID
, script, false);
 ScriptManager.RegisterHiddenField(this, this.UniqueID + "$SelectedText", this.SelectedText);
 ScriptManager.RegisterHiddenField(this, this.UniqueID + "$SelectedValue", this.SelectedValue);
 ScriptManager.RegisterHiddenField(this, this.UniqueID + "$SelectedIndex", this.SelectedIndex.ToString());
 }
 elseif (!this.DesignMode)
 {
 RenderScript(writer);
 Page.ClientScript.RegisterHiddenField(this.UniqueID + "$SelectedText", this.SelectedText);
 Page.ClientScript.RegisterHiddenField(this.UniqueID + "$SelectedValue", this.SelectedValue);
 Page.ClientScript.RegisterHiddenField(this.UniqueID + "$SelectedIndex", this.SelectedIndex.ToString());
 }
 }
}

例如,在示例的OnPreRender 方法中,路径和脚本 block的初始化方式与 ASP.NET 2.0版本中的方式相同。 这是因为 ScriptManager 没有实现一个检查脚本是否已经注册的方法,我假设这是由 register 方法本身完成的。

创建脚本字符串后,通过将控制页传递给 GetCurrent 方法的ScriptManager static,检索 ScriptManager的一个实例。 然后,检查 ScriptManger 实例以确定页是否实际包含 ScriptManager,如果是,则如果处理部分页面呈现( 一个 UpdatePanel 使用中)。 如果是,则JavaScript文件注册为 RegisterClientScriptBlock 方法的ScriptManager static ;否则,这与 ASP.NET 2.0版本中的方式相同。

使用 ScriptManager 还可以将由 RenderScript 方法编写的脚本 block 与 Render 方法进行 register。 由于 UpdatePanel 在不重新加载页面的情况下注入内容,因这里该脚本被浏览器视为纯文本节点。 在 ScriptManager 中注册 inline 脚本会导致它处理脚本的执行。

在使用 ScriptManager 注册脚本之前,确保它的实际可以能并且必须与 OnPreRender 方法相同的方式进行必要的检查。 获取 RenderScript 方法编写的脚本的技巧是在执行该方法后通过一个 StringWriter 实例传递一个新的HtmlTextWriter。 然后,通过调用方法的StringWriterToString 并通过调用方法的ScriptManagerRegisterStartupScript 进行注册来检索脚本。 否则,如果没有需要或者没有 ScriptManager的register,脚本的编写方式与 ASP.NET 2.0版本中的相同。

ASP.NET 2.0版本一样,Render 方法也为控件注册隐藏字段。 如果脚本需要被 ScriptManager 注册,隐藏字段也需要用 ScriptManager 注册,使控件能够正常工作。 否则,隐藏字段的注册方式与 ASP.NET 2.0版本中的相同。

用于AJAX输出的 AutoSuggestListPage

sql Server服务器控件库just服务器控件实现建议的原因是它实现了按 AutoSuggestTextBox 预期格式输出建议的AutoSuggestListPage。 创建 AutoSuggestList 控件是为了在设计视图中配置 AutoSuggestListPage

基本上,所有 AutoSuggestList 控件都是 AutoSuggestListBase 控件中的inherit 来提供数据绑定功能和分隔符属性。 因为本文中已经介绍了从属性网格输出HTML和隐藏属性,所以我不会提供任何代码示例。

AutoSuggestListPage 包含一个 protected 字段,用于访问包装的AutoSuggestList 属性,这样可以通过控件或者从 AutoSuggestListPage 属性访问它们。 AutoSuggestList 被声明为 因此,必须使用与 AutoSuggestListPage 页中的字段名称相同的ID来获得控件。 为确保 List 以 AutoSuggestTextBox 所期望的正确格式输出,基本 Page 类的OnLoadRender 方法被重写在下面的示例代码中。

protectedoverridevoid OnLoad(System.EventArgs e)
{
 this.Response.AddHeader("Content-Type", "text/xml");
 base.OnLoad(e);
}protectedoverridevoid Render(HtmlTextWriter output)
{
 if (!DesignMode)
 {
 output.WriteLine("<?xml version="1.0" encoding="utf-8"?>");
 output.WriteLine("<listdata>");
 bool multiValue = false;
 foreach (ListItem item inthis.Items)
 multiValue = (item.Text!= item.Value);
 if (multiValue)
 {
 for (int itemIndex = 0; itemIndex <this.Items.Count; itemIndex++)
 {
 if (itemIndex == 0)
 output.Write(this.Items[itemIndex].Text
 + this.TextValueDelimiter
 + this.Items[itemIndex].Value);
 elseif (itemIndex!= this.Items.Count - 1)
 output.Write(this.ItemDelimiter
 + this.Items[itemIndex].Text
 + this.TextValueDelimiter
 + this.Items[itemIndex].Value);
 else output.Write(this.ItemDelimiter
 + this.Items[itemIndex].Text
 + this.TextValueDelimiter
 + this.Items[itemIndex].Value);
 }
 }
 else {
 for (int itemIndex = 0; itemIndex <this.Items.Count; itemIndex++)
 {
 if (itemIndex == 0)
 output.Write(this.Items[itemIndex].Text);
 elseif (itemIndex!= this.Items.Count - 1)
 output.Write(this.ItemDelimiter
 + this.Items[itemIndex].Text);
 else output.Write(this.ItemDelimiter
 + this.Items[itemIndex].Text);
 }
 }
 output.Write(Environment.NewLine + "</listdata>");
 }
 elsebase.Render(output);
}

OnLoad 方法中发生的所有事情都是一个 header,将内容类型设置为 XML,并且基 PageOnLoad 方法被调用。 这是为了确保页面被浏览器视为XML文件,因这里JavaScript类可以正确地解析 List 项。

使用 Render 方法重写方法以输出带有 AutoSuggestList 控件指定的项和分隔符的建议 List,并防止基 Page 呈现任何其他元素。 如果在 DesignMode 中,基 Page 正常呈现,以便为编辑选择 AutoSuggestList 控件。

AutoSuggestListPage的项模板

在前一节中,我提到 AutoSuggestListPage 依赖于链接的ASPX文件上的AutoSuggestList 控件以正常工作。 在web项目中添加 AutoSuggestListPage 涉及添加新页面,更改类以继承 AutoSuggestListPage,并向从其中配置列表的页添加 AutoSuggestList 控件。 或者,只要使用提供的模板,并将 AutoSuggestListPage 添加到已经配置了需求 上面的项目中,然后直接配置列表。

创建模板是一个相当简单的过程。 只要在设计视图中轻松配置,模板就可以使用它们自己的向导构建它们,这实际上不是必需的。 创建这里模板所需的全部是在上面描述的AutoSuggestListPage 中实现,然后使用向导从菜单模板导出 Visual Studio 文件导出到模板。 菜单项。

历史记录

  • September。2009 - Version
    • 初始版本。

Server  控制  AUTO  asp  asp-net  Using  
相关文章