2009-09-10 82 views
6

alt text http://img3.imageshack.us/img3/1488/advancedsearch.png建议在ASP.NET

建立一个动态的“高级搜索”控制我建立在ASP.NET应用程序的“高级搜索”界面。我不需要为我写这个东西,但我被困在关于动态控件和ViewState的特定问题上。我想知道如何解决这个问题。这里是我的情况:

主料:

  • 一个维修组表示实体,字段和搜索API对象,它可以处理构建搜索,生成SQL,并返回结果。所有这一切都照顾好了。
  • ASP.NET 3.5

所需界面功能性:

(1)在初始页面加载,接口获取预先配置的搜索对象与一组SearchCriterion对象。它结合他们到一组控件

  • 一些搜索项目是简单的,像(见上图):

    场(的DropDownList)|运算符(DropDownList)|对于某些字段类型的值(文本框)

  • 搜索标准控制已存储的重要信息视图状态,如:

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

  • 某些字段查找到其它实体,这导致场选择的链,如:

    字段(DropDownList的)场(DropDownList的)|运算符(DropDownList)|值

(2)用户修改由所述搜索:

  • 添加和通过点击各个按钮通过改变字段,操作员或值
  • 配置现有标准卸下的搜索条件。对字段或操作员的更改将要求控件通过更改可用操作符,将“值”输入控件更改为其他类型,或者如果选择/取消选择查找类型字段,从“字段”部分添加/删除DropDownLists, 。

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

问题:

正如你可能已经知道,如果你回答这个问题,动态添加控件的页面消失回发。我已经创建了一个UserControl来操纵控件集合,并完整地完成上面的步骤(1),您可以在附加图像中看到它。 (很明显,我现在不关心风格。)

但是在Postback上,控件都没了,我的Search API对象也没有了。如果我可以让动态生成的控件集合在ViewState中很好地运行,我可以检查回发控件,重建搜索对象,然后整齐地处理控件事件。

可能的解决方案

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

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

  • 我在想我可以使用数据绑定控件来完成此操作 - 例如我可以将我的标准集合绑定到具有固定控件集合的中继器(可以隐藏未使用的“值”控件,使用“字段”下拉列表的内部中继器)。那么所有的信息将保持在ViewState中...对吗?

  • 任何新的想法将不胜感激。

感谢您的帮助。 b.Fandango

+0

这是一篇很棒的文章,我试图构建几乎完全一样的搜索页面。你介意分享你的初始工作的任何例子,即创建“一组代表实体,字段和搜索的可用API对象,它们处理构建搜索,生成SQL并返回结果。”如果你有任何链接或信息要共享,这将是非常有益的,只是担心,如果已经有libs /框架在做这种事情,我不想重新发明轮子。谢谢,伟大的职位! – russds 2013-07-18 17:28:20

+0

russds,我在一个中等规模的企业软件包上工作,该软件包有自己的元数据(实体和字段)和搜索实现。我无法与您分享我的雇主的任何源代码,尽管我确信他们不会介意我是否写过关于系统该部分的设计和实施。不过,我认为有很多“业务对象”基类库,可以为您提供这些类型的功能。我会看看我能为你找到什么,但我也建议你一边快速的谷歌。 – 2013-07-18 20:48:53

+0

谢谢巴里。我做了一些谷歌搜索,但不完全是谷歌,我尝试过诸如“动态搜索UI”和“asp.net高级搜索”之类的东西,但没有具体的结果。你的描述正是我正在寻找的内容,我会搜索什么样的术语?谢谢! – russds 2013-07-25 20:18:39

回答

4

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

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

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

2

由于没有人对此进行了2个小时的刺探,所以我会用一种不依赖viewstate的解决方案(或者ASP.NET的模型回发)。

如果你用jQuery抓取所有的输入值,而不是做一个后期做了一个针对该页面(或新的results.aspx页面)的帖子?或者,你可以让整个事情变得异常,并且针对Web方法做一个Ajax请求,得到结果并根据需要填充到客户端?

这里不幸的是你必须重建哪种类型的控件用于构建搜索查询,因为该数据不会与视图状态一起传递。但是我想你已经不得不将输入数据翻译成查询表单了。

阅读here了解更多关于使用jQuery命中ASP.NET页面方法的信息。记住 - 页面方法必须是静态的(这很容易忽略)。

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

这很好,因为1)LINQ是推迟执行和2)LINQ查询返回另一个可查询对象。这里的含义是,您可以在您的输入中构建LINQ查询时将其链接在一起,而不是必须对SQL执行单个大量子句转换或您正在使用的任何后端存储(我的一个尝试是使用字符串构造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查询)在执行时间。

+1

在这里评论我自己的答案,因为这与问题/答案无关,并且非常有见地 - 但这是我放弃使用ASP.NET来支持ASP.NET MVC的原因之一。HTTP协议不是有状态的,ViewState的ASP.NET模型实际上只是一个猴子补丁程序,可以在Web应用程序中获得状态。就这样,你遇到了这些问题。尽管可能有一个真正的ASP.NET/postback解决方案,但涉及到的复杂性开始超过了好处。毕竟,你只是试图发送数据回服务器!应该像馅饼一样容易。 – Matt 2009-09-10 18:33:39

+0

感谢您抽出宝贵时间来解释这一切。虽然它避免了ViewState的特定问题,但是它放弃了整个方法并引入了一些新的挑战。这有点“当你拥有的只是一把锤子时,所有东西看起来都像个钉子”解决方案 - 这是我在jQuery上看到的一些原因。 – 2009-09-11 13:50:24

+0

也感谢关于API和DB方面的建议,我知道这与问题无关,但我很欣赏听到关于该主题的另一个观点。 – 2009-09-11 13:51:10

2

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

对不起,我没有更多的帮助,但我没有与我(与老雇主)的代码。我希望这有帮助。

2

如果要动态地将控件添加到控件树中,则还需要将它们添加到Postpack中。只需调用在Page_Load或Page_Init上构建控件的方法,并且控件应保留在回发页面上。