Home » .net, Entity Framework, JavaScript, Other Tech

Search and Filter controls on an asp.net GridView/DetailsView Header Row (breaking out of a NamingContainer)

11 September 2009 No Comment

In this post we’re going to discuss breaking out of a naming container to set the value of a hiddenField for binding to a dataSource. The example will deal specifically with putting search and filter controls on the HeaderRow/HeaderTemplate of an asp.net GridView, but the applications go far beyond that.

To start, let’s have a look at our desired gridview filtering controls, starting with the AjaxControlToolkit AutoCompleteExtender deep-text search textBox discussed in this post:

This is a gridview with search and filtering controls in the header

This is a gridview with search and filtering controls in the header

As discussed, the search textbox searches multiple fields in our entity to help the user find the desired record:

Looking for all trips in October

Looking for all trips in October

Ordinarily, the problem you encounter when trying to put search/filter controls in a HeaderTemplate is that you can’t set your DataSource’s whereParameter ControlID to a control on a gridview, because they’re not in the same scope (NamingContainer), you’ll get an error like this:

System.InvalidOperationException: Could not find control ‘yourControlID’ in ControlParameter ‘yourParam’

If you’ve ever done a view source on an aspx page, you’ll notice that a control you made like this in Visual Studio:

<asp:HiddenField ID="txtTripId_hidden" runat="server" />

Looks something like this after it’s rendered in the browser:

<input type="hidden" id="ctl00__yourForm_txtTripId_hidden" />

Basically, any asp.net control that’s nested inside a NamingContainer (gridviewrow, content, etc) is going to have a unique ID generated at runtime.  That’s why you’re able to set the id of multiple textboxes to the same value if they’re on different templates of a gridviewrow.  If your hiddenfield is in a different container than your datasource, the datasource can’t “see” your hiddenfield.

We’re going to discuss two different approaches to this problem, and both build on what I outlined in the post on retrieving key/value pairs from an AutoCompleteItem.

Method 1 – Putting a hiddenField on your form and using the EntityDataSource’s WhereParameter:

Note the javascript in that post, because we’re going to be adding to it for this method.  I’m not going to re-type it all here, but you can stick the following snippet into the “autoCompleteItemSelected” method and be on your way:

//the underscore is a token in the id of the rendered control:
var splitSourceId = source.get_id().split('_');

if(splitSourceId.length > 2) {
     //this is just based on the namingConventions,
     //    try alert(splitSourceId) to see why we do this:
     var strippedSourceId = splitSourceId[0] + '__' + splitSourceId[2] + '_' + _
           splitSourceId[splitSourceId.length-1] + '_hidden';

     //try to find the hiddenField that's outside the gridview:
     var outerHidden = document.getElementById(strippedSourceId);
     if(outerHidden)
          outerHidden.value = eventArgs.get_value();
}

The nice thing about this is, you add it to your shared javascript function, and it doesn’t interfere with anything. I was using the function on 3 other pages before I added this, and it’s inconsequential if you’re not trying to use it.

So what we’ve just done there is set a root-level control (hiddenField)’s value to our Id that we want to filter on. Now we can reference the hiddenField in our EntityDataSource and be good to go! For this trip gridview, our dataSource will look like so:

<asp:EntityDataSourceID="entTripSource" runat="server"
 ConnectionString="name=BusLineEntities"
 DefaultContainerName="BusLineEntities"
 EntitySetName="ExecutiveTrips"
 AutoGenerateWhereClause="true">
 <WhereParameters>
 <asp:ControlParameter ControlID="txtTripSearch_hidden"
Type="Int32" Name="Id" />
 </WhereParameters>
</asp:EntityDataSource>

You might notice it’s not posting back like you’d expect. You need to cause the postback at some point, which I’ve done by using the TextChanged event of our input textbox (this makes it immediate when the user selects an item from the autoComplete dropdown, no “apply filter” button is needed).

<asp:TextBox ID="txtPassenger_input" runat="server"
        AutoPostBack="true" OnTextChanged="someMethod" Width="200px" />

That works very well for when you only want to search. In some cases, though, you want even more functionality, like filtering on a range of values, that’s where method 2 comes in.

Method 2:

Coming soon…

Leave your response!

Add your comment below, or trackback from your own site. You can also subscribe to these comments via RSS.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

This is a Gravatar-enabled weblog. To get your own globally-recognized-avatar, please register at Gravatar.