带有项搜索的DropDownList控件,使用回调

分享于 

11分钟阅读

Web开发

  繁體

DDL with search

Search query form

Search result

介绍

当我参与一个项目时,我们面临着在控件中表示不同实体的巨大的集合。 如果所有项绑定到控件,则页的大小可能为 GREATER,而不是 2 -3 MB。 当然,它并不合适,并且在 DropDownList 控件中添加了搜索功能来解决这个问题。 这样,用户可以指定搜索条件并减少项目集。 为了减少回发数量,还可以使搜索控制 compact 和适当的一些问题。 使用回调和JavaScript组合解决了 上面 中提到的所有问题。

背景

当控件绑定到数据源时,它检查其中的对象数。 如果绑定对象数超出了定义的限制,控件将呈现自身,如第一张图片所示。 当用户按下 search button 按钮,用于输入搜索查询的窗体出现在下拉列表中。 这里窗体显示在第二个图像上。 在输入查询之后,用户应该按 go button 按钮,并且控件将向服务器发送回调。 返回的结果是满足指定搜索查询的项的集合。 在这里示例中,用户指定上限值,并且 DropDownList 由小于该值的整数填充。

实现

服务器控件 DDLWithSearch 是从标准继承 System.Web.UI.WebControls.DropDownList ,并实现这样的接口, System.Web.UI.ICallbackEventHandlerSystem.Web.UI.IPostBackDataHandler。在客户端,它使用在 DDLWithSearchCoreClass 中定义的JavaScript函数。 将JavaScript文件作为嵌入资源编译到控制程序集。 这里控件定义一些数据操作事件:

  • 返回 GetObjectsListCount - 被激发以检索满足搜索条件的项列表的大小。
  • GetObjectsList - 被激发以检索满足搜索条件的项的列表。
  • GetObjectByID - 被激发以检索被它的标识绑定的对象。

以及以下属性:

  • MaxRenderItemsCount - 如果绑定对象数超过这里限制,则控件呈现搜索控件。
  • MaxCallbackItemsCount - 可以作为回调结果返回的最大项数。
  • EnableSelectItem - 启用或者禁用'选择。'项。
  • SelectItemText - 默认情况下,这里设置设置为'选择。'。
  • UseSearchItemText - 默认情况下,这里设置设置为'请使用搜索'。
  • NoItemsFoundItemText - 默认情况下,这里设置设置为'找不到项目'。
  • TooBigResultItemText - 默认情况下,这里设置设置为'结果太大'。
  • ClientCallbackErrorHandler - 指定调用时调用的JavaScript函数 NAME。
  • EnableSearch - 启用或者禁用搜索控件。

在客户端可以更改项时,控件实现 System.Web.UI.IPostBackDataHandler 接口。 使用选项 Collection 所做的更改存储在两个隐藏的输入元素中,这些元素在 OnPreRender 方法中注册。 此外,在这里方法中,DDLWithSearch.js 文件和回调hadlers也被注册:

protectedoverridevoid OnPreRender(EventArgs e)
{
 base.OnPreRender(e);
 if (!this.Page.ClientScript.IsClientScriptBlockRegistered("DDLWithSearch"))
 {
 // Define the resource name and type.this.Page.ClientScript.RegisterClientScriptInclude(
 this.GetType(), "DDLWithSearch",
 Page.ClientScript.GetWebResourceUrl(this.GetType(),
 "DDLWithSearch.DDLWithSearch.js"));
 }
 if ((_searchMode == SearchMode.SearchIsOn) || EnableAddItemsOnClient)
 {
 Page.ClientScript.RegisterHiddenField(string.Format("{0}{1}", 
 hiddenItemsPrefix, this.ClientID), string.Empty);
 Page.ClientScript.RegisterHiddenField(string.Format("{0}{1}", 
 hiddenSelectedPrefix, this.ClientID), string.Empty);
 string callBackRef = null;
 if(ClientCallbackErrorHandler == string.Empty)
 {
 // Without Error handle callBackRef = Page.ClientScript.GetCallbackEventReference(
 // controlthis,
 // argument - the value of the txtSearch"document.getElementById('srchTextBox').value",
 // client call back function"DDLWithSearchCore.ReceiveDdlItems",
 // context - ddl idstring.Format("'{0}'", this.ClientID)
 );
 }
 else { 
 //With Error handle callBackRef = Page.ClientScript.GetCallbackEventReference(
 // controlthis,
 // argument - the value of the txtSearch"document.getElementById('srchTextBox').value",
 // client call back function"DDLWithSearchCore.ReceiveDdlItems",
 // context - ddl idstring.Format("'{0}'", this.ClientID),
 ClientCallbackErrorHandler,
 false );
 }
 this.Attributes.Add(attrRunSearchStatement, 
 string.Format("javascript:DDLWithSearchCore" + 
 ".PrepareDdlToCallBack('{0}') && {1}", 
 this.ClientID, callBackRef));
 }
}

BindItems 方法检查绑定对象的数目,如果需要,将设置 SearchMode.SearchIsOn 模式:

publicvoid BindItems()
{
 // get the number of objectsint objectsCount = _GetObjectsListCount(string.Empty);
 if (objectsCount > MaxRenderItemsCount && 
 _searchSettings == SearchSettings.SearchEnabled)
 {
 _searchMode = SearchMode.SearchIsOn;
 this.Items.Clear();
 this.Items.Add(new ListItem(UseSearchItemText, this.NoneItemValue));
 }
 else {
 this.DataSource = _GetObjectsList(string.Empty);
 this.DataBind();
 if (EnableSelectItem)
 {
 this.Items.Insert(0, new ListItem(this.SelectItemText, 
 this.NoneItemValue));
 }
 }
}

GetCallbackResult 方法获取和准备满足搜索查询的项的Collection:

publicstring GetCallbackResult()
{
 ClientItemsCollection clientItemsCollection = new ClientItemsCollection();
 int objectsCount = _GetObjectsListCount(_callBackSearchQuery);
 if (objectsCount >0)
 {
 if (objectsCount < MaxCallbackItemsCount)
 {
 IEnumerator objectsListEnumerator = 
 _GetObjectsList(_callBackSearchQuery).GetEnumerator();
 StringBuilder sb = new StringBuilder();
 if (this.EnableSelectItem)
 {
 clientItemsCollection.AddItem(this.SelectItemText, 
 this.NoneItemValue);
 }
 while (objectsListEnumerator.MoveNext())
 {
 PropertyInfo piDataValue = null;
 PropertyInfo piDataText = null;
 if(piDataValue == null)
 {
 piDataValue = 
 objectsListEnumerator.Current.GetType().GetProperty(
 this.DataValueField, 
 BindingFlags.Instance|BindingFlags.Public);
 if (piDataValue == null)
 thrownew PropertyNotFoundExeption(this.DataValueField);
 piDataText = 
 objectsListEnumerator.Current.GetType().GetProperty(
 this.DataTextField, BindingFlags.Instance | 
 BindingFlags.Public);
 if (piDataText == null)
 thrownew PropertyNotFoundExeption(this.DataTextField);
 }
 string dataValue = 
 piDataValue.GetValue(objectsListEnumerator.Current, 
 null).ToString();
 string dataText = 
 piDataText.GetValue(objectsListEnumerator.Current, 
 null).ToString();
 clientItemsCollection.AddItem(dataText, dataValue);
 }
 }
 else {
 clientItemsCollection.AddItem(this.TooBigResultItemText, 
 this.NoneItemValue);
 }
 }
 else {
 clientItemsCollection.AddItem(this.NoItemsFoundItemText, 
 this.NoneItemValue);
 }
 return clientItemsCollection.GetClientString();
}

此外,SelectedValue 属性还需要一些更改:

publicnewstring SelectedValue
{
 get {
 returnbase.SelectedValue;
 }
 set {
 // Check if there is already such item in list ListItem item = Items.FindByValue(value);
 if (item == null)
 {
 object newItemObject = _GetObjectByID(value);
 if (newItemObject!= null)
 {
 Type objType = newItemObject.GetType();
 PropertyInfo textFieldProperty = 
 objType.GetProperty(this.DataTextField);
 PropertyInfo valueFieldProperty = 
 objType.GetProperty(this.DataValueField);
 string itemText = Convert.ToString(
 textFieldProperty.GetValue(newItemObject, null));
 string itemVal = Convert.ToString(
 valueFieldProperty.GetValue(newItemObject, null));
 this.Items.Add(new ListItem(itemText, itemVal));
 }
 else {
 thrownew InvalidItemValueException();
 }
 }
 base.SelectedValue = value;
 }
}

使用代码

要在项目中使用该控件,应执行以下操作:

  • 添加对程序集 DDLWithSearch.dll.的引用
  • 从 $ProjectDir$Styles 复制 ddlWithSearch.css 和图像文件夹到主题目录。

DDLWithSearch.js 文件作为嵌入资源编译,不应手动引用。

要在页上使用这里控件,应执行以下操作:

  • 为事件所激发的事件定义事件处理程序
  • 设置 DataTextFieldDataValueField 属性

这是一个使用示例:

ddlTest.GetObjectsListCount += new 
 DDLWithSearch.DDLWithSearch.GetObjectsListCountEventHandler(
 ddlTest_GetObjectsListCount);
ddlTest.GetObjectsList += new 
 DDLWithSearch.DDLWithSearch.GetObjectsListEventHandler(
 ddlTest_GetObjectsList);
ddlTest.GetObjectByID += new 
 DDLWithSearch.DDLWithSearch.GetObjectByIdEventHandler(
 ddlTest_GetObjectByID);
ddlTest.DataTextField = "TestText";
ddlTest.DataValueField = "TestValue";
ddlTest.BindItems();

使用示例在 IE 6,Firefox 1.5和 Opera 8.54中工作正常。

历史记录

  • 9 2006年月 - 已经提交文章。

相关文章