To read the article online, visit http://www.4GuysFromRolla.com/articles/092502-1.2.aspx

An Extensive Examination of the DataGrid Web Control: Part 10, Part 2

By Scott Mitchell


Read Part 1


In Part 1 we looked at adjusting the BindData() subroutine so that it would accept an input parameter and, when called, display a DataGrid that contained the FAQs with a particular FAQCategory value. In this part we'll look at designing the user interface to allow the end user to determine which categories FAQs they wish to view.

Displaying Hyperlinks for Each FAQ Category


As discussed in Part 1 of this article, an ideal way to allow the user to decide what FAQ category she wished to view the FAQs of would be to provide a listing of all of the FAQ categories at the top of the page in hyperlink form. When one of these hyperlinks was clicked, the ASP.NET page would postback, the BindData(FilterOnFAQCategoryID) subroutine would be called with the proper FilterOnFAQCategoryID passed in, and the DataGrid would have the proper subset of FAQs displayed.

One way to accomplish this would be to just add a hyperlink for each FAQ category, like so:

<form runat="server">
  <asp:LinkButton runat="server" Text="Application Object"
        CommandArgument="7" OnCommand="FilterData" />
  <asp:LinkButton runat="server" Text="Arrays"
        CommandArgument="1" OnCommand="FilterData" />
  ...
  <asp:LinkButton runat="server" Text="Uploading"
        CommandArgument="19" OnCommand="FilterData" />


  <asp:DataGrid runat="server" id="dgFilteredFAQs" ...>
    ...
  </asp:DataGrid>
</form>

The CommandArgument property corresponds to the particular FAQ category's FAQCategoryID value. That is, all FAQs that fall under the "Application Object" category have a FAQCategoryID value of 7; all FAQs that fall under the "Array" category have a FAQCategoryID value of 1; etc. The DataGrid shown in the above code snippet is the actual DataGrid that the BindData(FilterOnFAQCategoryID) subroutine binds its results to - that is, it is the DataGrid that will display the FAQs for the particular FAQ category.

Given the above code, all that we would need to do is add an event handler named FilterData for the various LinkButtons' Command events. The code for this event handler would be insanely short and simple, consisting of just one line of code: namely, it would make a call to the BindData(FilterOnFAQCategoryID) subroutine passing in the value of the CommandArgument property as the input parameter. In code, it would look like:

  Sub FilterData(sender as Object, e as CommandEventArgs)
	BindData(e.CommandArgument)
  End Sub

When a user clicks on of these LinkButtons, the ASP.NET page is posted back, and the Command event of the clicked LinkButton is raised. This triggers the FilterData event handler to run, which calls the BindData(FilterOnFAQCategoryID) subroutine, passing in the value of the clicked LinkButton's CommandArgument property as the FilterOnFAQCategoryID parameter, which has the effect of having the DataGrid display those FAQs of that particular FAQCategoryID.

Improving the Code - Removing the Hardcoded LinkButtons


The above code that uses a hardcoded LinkButton for each FAQ category will work, but it's messy for two reasons. First of all, had I actually taken the time to write the code for this page, I'd have to create a LinkButton for each FAQ - all 21 of them. Additionally, I'd have to find out the FAQCategoryID associated with each FAQ and set the LinkButton's CommandArgument property accordingly. On top of this, if I added or removed any FAQ categories from the database, I'd have to edit this Web page (adding new LinkButtons when new FAQ categories were added and removing LinkButtons when FAQ categories were removed).

A better approach would be to have the FAQ category LinkButtons generated dynamically. Recall from Dynamic Controls in ASP.NET that controls can be added dynamically via the Add method of the Controls collection (a collection each and every Web control has). To add our needed LinkButtons dynamically we'll first create a PlaceHolder control to mark where these LinkButtons should be added in the HTML content. Next, we'll perform a SQL query that will populate a SqlDataReader with the various FAQ categories. We can then iterate through this SqlDataReader adding a LinkButton for each row.

The following code provides a subroutine (AddFilterButtons()) that dynamically creates the needed LinkButtons. It adds each LinkButton to a PlaceHolder named phFilterLinkButtons, which appears in the HTML section (see the code at the bottom of the live demo for more details). Also note that some HTML markup (namely, a pipe symbol (|)) is added between each LinkButton to make it easier to read.

Sub AddFilterButtons()
  'Get a list of the categories
  '2. Create the command object, passing in the SQL string
  Dim strSQL as String 
  strSQL = "SELECT FAQCategoryID, Name AS CategoryName " & _
           "FROM tblFAQCategory " & _
           "ORDER BY CategoryName"

  'Set the datagrid's datasource to the datareader and databind
  Dim myConnection as New _
      SqlConnection(ConfigurationSettings.AppSettings("connectionString"))
  Dim myCommand as SqlCommand = New SqlCommand(strSQL, myConnection) 
    
  myConnection.Open()
  Dim myDataReader as SqlDataReader = myCommand.ExecuteReader()
    
  'Loop through the results, creating a LinkButton for each row
  Dim filterButton as LinkButton
  While myDataReader.Read()
    'Add the LinkButton
    filterButton = New LinkButton()
    filterButton.Text = myDataReader("CategoryName")
    filterButton.CommandArgument = myDataReader("FAQCategoryID")
    AddHandler filterButton.Command, AddressOf Me.FilterData      
      
    phFilterLinkButtons.Controls.Add(filterButton)
      
    'Add some white space
    phFilterLinkButtons.Controls.Add(New LiteralControl(" | "))
  End While
    
  myDataReader.Close()
  myConnection.Close()    
End Sub
[View a Live Demo!]

The AddFilterButtons() subroutine needs to be called in the Page_Load event handler so that the LinkButtons are created on each page load. By default, dynamically created controls are not saved to the Page's ViewState, meaning that they are lost across postbacks. If you want to save a dynamically created control in the ViewState you must do it explicitly, using ViewState("ViewStateKey") = ControlName.PropertyToSave to save one of the control's properties, and ControlName.PropertyToSave = ViewState("ViewStateKey") to restore it. Without saving the LinkButtons in the ViewState you are having to incur a database access every page view to grab the list of FAQ categories.

Take a moment to check out the live demo. Note that the AddFilterButtons() subroutine is indeed called in the Page_Load event handler, and where the phFilterLinkButtons PlaceHolder control appears in the HTML markup.

Conclusion


In this article we saw how to create filtering buttons for a DataGrid control. Once we made a slight edit to our original BindData() function this added feature was as easy as adding the LinkButtons to complete the user interface and providing a (one-line) event handler for the LinkButtons' Command events. In addition, we saw how to dynamically add a LinkButton for each unique FAQ category in the database. Dynamically adding the controls has the advantage of saving time from typing in hardcoded LinkButtons and, more importantly, saves us editing time when the FAQCategories table is added to or deleted from.

Happy Programming!

  • By Scott Mitchell

  • Article Information
    Article Title: ASP.NET.An Extensive Examination of the DataGrid Web Control: Part 10, Part 2
    Article Author: Scott Mitchell
    Published Date: September 25, 2002
    Article URL: http://www.4GuysFromRolla.com/articles/092502-1.2.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers