在ASP.NET中构建动态“高级搜索”控件的建议

时间:2009-09-10 15:54:39

标签: asp.net search dynamic viewstate

alt text http://img3.imageshack.us/img3/1488/advancedsearch.png

我正在ASP.NET应用程序中构建“高级搜索”界面。我不需要为我写这个东西,但我坚持一个关于动态控件和ViewState的特定问题。我想知道如何处理这个方向。这是我的情况:

成分:

  • 一组可维护的API对象,表示实体,字段和搜索,用于处理构建搜索,生成SQL和返回结果。所以这一切都得到了照顾。
  • ASP.NET 3.5

所需的界面功能:

(1)在初始页面加载时,界面获得一个预先配置的Search对象,其中包含一组SearchCriterion对象。它将它们绑定到一组控件中(参见上图。)

  • 有些搜索项比较简单,例如:

    Field(DropDownList)|运算符(DropDownList)|价值(TextBox)

  • 某些字段类型的搜索条件控件具有存储在viewstate中的重要信息,例如:

    Field(DropDownList)|运算符(DropDownList)|值(DropDownList),其中“值”下拉列表由数据库查询填充。

  • 某些字段是对其他实体的查找,这会导致一系列字段选择器,例如:

    Field(DropDownList)字段(DropDownList)|运算符(DropDownList)|值

(2)用户通过以下方式修改搜索:

  • 点击相应的按钮
  • 添加和删除搜索条件
  • 通过更改字段,运算符或值来配置现有条件。如果选择/取消选择查找类型字段,则对字段或运算符的更改将要求控件通过更改可用运算符,将“值”输入控件更改为其他类型或从“字段”部分添加/删除DropDownLists来重新配置自身

(3)最后,用户点击“搜索”以查看他们的结果。

问题:

正如您可能已经知道如果您正在回答此问题,动态添加到页面的控件会在回发时消失。我已经创建了一个UserControl来操作控件集合并巧妙地完成上面的步骤(1),如附图所示。 (显然,我现在并不关心风格。)

然而,在Postback上,控件全部消失,我的Search API对象消失了。如果我可以让动态生成的控件集合发挥得很好并坚持使用ViewState,我可以检查回发上的控件,重建Search对象,然后整齐地处理控件事件。

可能的解决方案

  • 我可以将Search对象序列化并将其存储在viewstate中。然后在页面加载时我可以抓住它并在页面加载时重建控件集合。但是我不确定这是否可以很好地控制引发事件,以及包含数据库数据的下拉列表的视图状态会发生什么 - 我可以把它取回来吗?我不得不在每次回发时重新查询数据库。

  • 我可以为这种事情开发一个自定义服务器控件(see this link)......但这对我来说是一个新主题,并且会涉及一些学习,而且我不完全确定是否自定义服务器控件可以更好地与非固定控件集合一起使用。有人知道吗?

  • 我在想我可能能够使用数据绑定控件实现这一点 - 例如,我可以将我的标准集合绑定到具有固定控件集合的转发器(可能隐藏未使用的“值”控件,使用内部转发器作为“字段”下拉列表)。然后所有信息都将保留在ViewState中......对吗?

  • 非常感谢任何新想法。

感谢您的帮助。 b.Fandango

4 个答案:

答案 0 :(得分:4)

我已经编写了大约一天的时间,并且使用我在我的问题中建议的第三个选项 - 老式数据绑定控件,让我的工作非常漂亮。实际上,当我被迫详细地写出这个问题时,我只想到了这个想法 - 这不就是一直发生在你身上吗?

我将SearchCriterionControl放入asp:Repeater并将其绑定到我的对象集合。对于Field Chooser,我在嵌套的asp:Repeater中放置了一个asp:DropDownList,并将Field数组绑定到该数组。一切都很好,保持状态,实际上只需要很少的代码。所以我从来没有动态添加控件到页面,谢天谢地。

感谢您的建议,Ender,Matt和andrewWinn。

答案 1 :(得分:2)

由于没有其他人对此进行了2个小时的攻击,我将使用一个完全不依赖于viewstate的解决方案(或回发的ASP.NET模型)将我的帽子扔进戒指。

如果您使用jQuery抓取所有输入值并且不进行回发而是针对该页面发布了一个帖子(或新的results.aspx页面),该怎么办?或者,您可以使整个事情变得异常,并针对Web方法执行Ajax请求,获取结果,并根据需要填充客户端?

这里不幸的是你必须重建使用哪种类型的控件来构建你的搜索查询,因为这些数据不会与viewstate一起传递。但我想你无论如何都必须将输入数据转换成查询形式。

阅读here以获取有关使用jQuery命中ASP.NET页面方法的更多信息。请记住 - 页面方法必须是静态的(这是一个容易的疏忽)。

我不确定你在服务器端构建查询的是什么 - 但我高度推荐LINQ。之前我做过类似的“高级搜索”功能,经过几次不同的尝试后发现LINQ对于这个问题来说是一个很好的工具,不管我是用LINQtoSQL来打SQL还是只打一个内存中的对象集合。

这非常有效,因为1)LINQ是延迟执行,2)LINQ查询返回另一个可查询对象。这里的含义是,您可以在从输入构造LINQ查询时将它们链接在一起,而不必对SQL或您正在使用的任何backstore执行单个大规模子句转换(我的一个尝试是使用字符串构造SQL子句,但是仍然通过SQLParameters为SQL注入保护传递输入数据 - 当手工制作的LINQ更易于理解和实现时,它变得混乱和复杂。

例如:

List<string> data; // or perhaps your a DB Context for LINQtoSQL?

var query = data.Where(item => item.contains("foo"));

if( {user supplies length search option} )
    query = query.Where(item => item.Length < 5);

// etc, etc.

// LINQ doesn't do anything until the query is iterated, at which point
// it will construct the SQL statement without you worrying about details or parameter binding
foreach(string value in query)
    ; // do something with the results

由于延迟执行和可查询的返回类型,您可以整天将LINQ查询连接到此表达式,并让它在执行时担心实现细节(例如转换为SQL查询)。

答案 2 :(得分:2)

我无法向您提供您需要执行的确切步骤,但我强烈建议您查看asp.net页面生命周期。我创建了一个用户控件作为DLL一次。我必须在生命周期的特定步骤捕获回发数据,并在其他步骤重新创建和重新绑定数据。此外,像viewstate这样的想法也只在某些点可用。我知道我必须重写On_init,On_prerender和其他一些方法。

抱歉,我无法提供更多帮助,但我没有这些代码(与老雇主一起)。我希望这会有所帮助。

答案 3 :(得分:2)

如果要动态地向控件树添加控件,则还需要在postpack上添加它们。只需调用在Page_Load或Page_Init上构建控件的方法,控件应该在回发时保留在页面上。