R – Advice for Building a dynamic “Advanced Search” Control in ASP.NET

asp.netdynamicsearchviewstate

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

I'm building an "Advanced Search" interface in an ASP.NET application. I don't need SO to write this thing for me, but I'm stuck on a specific problem regarding dynamic controls and ViewState. I would like some direction for how to approach this. Here's my situation:

Ingredients:

  • A serviceable set of API objects representing entities, fields, and searches, which handles constructing a search, generating SQL, and returning the results. So that's all taken care of.
  • ASP.NET 3.5

Desired Interface Functionality:

(1) On initial page load, the interface gets a preconfigured Search object with a set of SearchCriterion objects. It binds them into a set of controls (see image above.)

  • Some search items are simpler, like:

    Field (DropDownList) | Operator (DropDownList) | Value (TextBox)

  • Search Criterion controls for some field types have important information stored in viewstate, like:

    Field (DropDownList) | Operator (DropDownList) | Value (DropDownList) where the "Value" dropdownlist is populated by a database query.

  • Some fields are lookups to other Entities, which causes a chain of field selectors, like:

    Field (DropDownList) Field (DropDownList) | Operator (DropDownList) | Value

(2) The user modifies the search by:

  • Adding and Removing search criteria by clicking respective buttons
  • Configuring existing criteria by changing the Field, Operator, or Value. Changes to Field or Operator will require the control to reconfigure itself by changing the available operators, changing the "Value" input control to a different type, or adding/removing DropDownLists from the "Fields" section if Lookup-type fields are selected/unselected.

(3) Finally, the user hits "Search" to see their results.

The Problem:

As you probably already know if you're answering this question, controls added dynamically to the page disappear on postback. I've created a UserControl that manipulates the control collection and neatly accomplishes step (1) above as you can see in the attached image. (I'm not concerned about style at this point, obviously.)

However on Postback, the controls are all gone, and my Search API object is gone. If I could get the dynamically generated control collection to just play nice and stick in ViewState, I could examine the controls on postback, rebuild the Search object, then handle control events neatly.

Possible Solutions

  • I could make the Search object serializable and store it in viewstate. Then on page load I could grab it and reconstruct the control collection at page load time. However I'm not sure if this would play nicely with controls raising events, and what happens to the viewstate of Drop-down lists that contain data from the database – could I get it back? It's highly undesirable for me to have to re-query the database on every postback.

  • I could develop a custom server control (see this link) for this kind of thing… but that is a new topic for me and would involve some learning, plus I'm not totally sure if a custom server control would work any more nicely with non-fixed control collections. Anybody know about that?

  • I was thinking that I might be able to accomplish this using databound controls – for example I could bind my criterion collection to a repeater which has a fixed control collection (maybe hide the non-used "value" controls, use an inner repeater for the "Field" drop-down lists). Then all the information would stay in ViewState… right?

  • Any new ideas would be greatly appreciated.

thanks for your help.
b.Fandango

Best Answer

I've been coding for about a day and I got this working beautifully using the third option I suggested in my question - old-school databound controls. Actually I only thought of the idea when I was forced to write out the question in detail - doesn't that just happen to you all the time?

I put my SearchCriterionControl into an asp:Repeater and bound it to my object collection. For the Field Chooser I put an asp:DropDownList inside a nested asp:Repeater and bound the Field array to that. Everything works beautifully, keeps state, actually required very little code. So I never had to dynamically add controls to the page, thank goodness.

Thanks for your suggestions, Ender, Matt and andrewWinn.