代码之家  ›  专栏  ›  技术社区  ›  James Orr

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

  •  6
  • James Orr  · 技术社区  · 15 年前

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

    我正在ASP.NET应用程序中构建“高级搜索”界面。我不需要这样来为我写这篇文章,但是我在关于动态控件和视图状态的特定问题上遇到了困难。我想知道如何处理这个问题。我的情况是:

    成分:

    • 一组可服务的API对象,表示实体、字段和搜索,用于构造搜索、生成SQL和返回结果。所以一切都处理好了。
    • ASP.NET 3.5

    所需的接口功能:

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

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

      字段(DropDownList)运算符(DropDownList)值(文本框)

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

      字段(DropDownList)运算符(DropDownList)值(DropDownList),其中“值”DropDownList由数据库查询填充。

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

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

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

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

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

    问题:

    正如您可能已经知道是否要回答这个问题一样,动态添加到页面的控件将在回发时消失。我已经创建了一个用户控件,它可以操作控件集合,并整齐地完成上面的步骤(1),如您在附加图像中看到的那样。(显然,我现在不关心风格。)

    但是在回发时,控件都消失了,我的搜索API对象也消失了。如果我可以让动态生成的控件集合只在viewstate中正常播放,我可以检查回发时的控件,重建搜索对象,然后整齐地处理控件事件。

    可能的解决方案

    • 我可以使搜索对象序列化,并将其存储在viewstate中。然后在页面加载时,我可以获取它并在页面加载时重建控件集合。但是,我不确定这是否能很好地处理引发事件的控件,以及包含数据库数据的下拉列表的视图状态会发生什么情况-我可以取回它吗?我非常不希望每次回发时都重新查询数据库。

    • 我可以开发一个自定义服务器控件( see this link )对于这种事情…但这对我来说是一个新的主题,需要学习一些知识,而且我不完全确定自定义服务器控件是否能更好地与非固定控件集合一起工作。有人知道吗?

    • 我在想,我可以使用数据绑定控件来实现这一点——例如,我可以将标准集合绑定到具有固定控件集合的中继器(可能隐藏未使用的“值”控件,将内部中继器用于“字段”下拉列表)。那么所有的信息都将保持在视图状态…正确的?

    • 任何新的想法都会受到极大的赞赏。

    谢谢你的帮助。 范丹戈

    4 回复  |  直到 12 年前
        1
  •  4
  •   James Orr    15 年前

    我已经编码了大约一天,使用我在问题中建议的第三个选项——老派的数据绑定控件,我很好地完成了这个工作。事实上,我只是在被迫详细写下这个问题的时候才想到这个主意——这不是一直都发生在你身上吗?

    我将searchCriterionControl放入一个asp:repeater并将其绑定到我的对象集合。对于字段选择器,我将一个asp:DropDownList放在嵌套的asp:Repeater中,并将字段数组绑定到它。所有的东西都很好地工作,保持状态,实际上只需要很少的代码。所以我从不需要动态地向页面添加控件,谢天谢地。

    感谢你的建议,恩德,马特和安德烈。

        2
  •  2
  •   Matt    15 年前

    由于2个小时内没有其他人对此进行过尝试,所以我将用一种完全不依赖于ViewState的解决方案(或Postbacks的ASP.NET模型)来向圈中扔帽子。

    如果您用jquery获取了所有输入值,而不是对页面(或新的results.aspx页面)执行回发操作,该怎么办?或者,您可以使整个事情异步化,对Web方法执行Ajax请求,得到结果,并根据需要在客户端进行填充?

    不幸的是,您必须重新构造用于构造搜索查询的控件类型,因为该数据不会随ViewState一起传递。但我想您已经需要将输入数据转换为查询表单了。

    here 有关使用jquery命中ASP.NET页方法的详细信息。记住-page方法必须是静态的(这是一个简单的监督)。

    我不知道您在服务器端做什么来构造您的查询——但是我会的。 高度地 推荐Linq。我以前做过一个类似的“高级搜索”功能,经过几次不同的尝试,我发现linq是解决这个问题的一个很好的工具,不管我是用linqtosql访问SQL还是只访问内存中的对象集合。

    这非常有效,因为1)Linq被延迟执行,2)Linq查询返回另一个可查询对象。这里的含义是,当您从输入构造LINQ查询时,您可以将它们链接在一起,而不必将单个大型子句转换为SQL或您正在使用的任何后台存储(我的一个尝试是用字符串构造SQL子句,但仍然通过用于SQL注入保护的sqlparameters传递输入数据)。当手工制作的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查询)。

        3
  •  2
  •   andrewWinn    15 年前

    我无法为您提供所需的具体步骤,但我强烈建议您研究ASP.NET页面生命周期。我曾经创建了一个用户控件作为DLL。我必须在生命周期的特定步骤中捕获回发数据,并在其他步骤中重新创建和重新绑定数据。此外,像viewstate这样的thinkgs也只能在某些点上使用。我知道我必须重写init、prerender和其他一些方法。

    很抱歉,我帮不上忙,但我身上没有密码(是给一个老雇主的)。我希望这有帮助。

        4
  •  2
  •   Ender    15 年前

    如果要动态地将控件添加到控件树中,还需要在后置时添加它们。只需调用在page_load或page_init上构建控件的方法,控件在回发时应保留在page上。