GridView, DetailsView, and SqlDataSource Interaction Part 1


The GridView, DetailsView, and SqlDataSource controls are good at setting up a data-driven web site. However, there are times when you need to take other factors into consideration, to improve the user experience. Part 1 of this series will look at some of the basic things that can be done.
By: Brian Mains Spacer Date: May 9, 2007

Introduction

This article will show you how you can use the GridView, DetailsView, and SQLDataSource controls together to create a comprehensive web site. This will be a multipart article talking about the various facets of using these three articles together. The article will make use of the AdventureWorks database, so if you do not have that installed, you can download it freely from Microsoft's web site. In addition, this article assumes you have an understanding of the GridView, DetailsView, and SqlDataSource controls, and how they can interrelate on a basic scale. It is also helpful to understand the various parameters of the data source controls, and how they can automatically map to server controls, query string values, and other sources.

Data Source Initial Binding

Sometimes you want to late-bind a GridView, for several reasons. Binding a GridView immediately means that it will hit against the database, even if no valid criteria have been passed to the parameter. There are several ways to stop this. The first is to not assign the DataSourceID property initially; this will prevent the gridview control from binding immediately, and show the EmptyDataText or EmptyDataTemplate message.

Another way to prevent loading the data if no results are present is to catch the data source's Selecting event handler, and cancel the query as such:

    void sdsSearch_Selecting ( object sender, ObjectDataSourceSelectEventArgs e )

    {

        e.Cancel = string.IsNullOrEmpty ( this.txtSearchText.Text );

    }

This works well in preventing the query, but does not prevent the empty data message from appearing in the GridView. Late-binding handles that.

Handling Multiple Data Sources

There is another reason to late-bind the DataSourceID property. There may be multiple sources; for instance, the application can have multiple data source controls. Take for instance, a product search. You may search a product by letter, by name, or by a category, for example. Each of these means can be its own data source. When the user chooses the appropriate search mechanism, the code-behind page attaches that data source control to the grid and a binding occurs, such as below:

    void lnkLetterSelection_Click ( object sender, EventArgs e )

    {

        this.gvwResults.DataSourceID = this.sdsLetter.ID;

        this.gvwResults.DataBind ( );

    }

 

    void lnkTextSearch_Click ( object sender, EventArgs e )

    {

        this.gvwResults.DataSourceID = this.sdsSearch.ID;

        this.gvwResults.DataBind ( );

    }

 

    void lnkCategorySelection_Click ( object sender, EventArgs e )

    {

        this.gvwResults.DataSourceID = this.sdsCategory.ID;

        this.gvwResults.DataBind ( );

    }

In this manner, the gridview is late-bound with the correct data store. In this case, enabling viewstate for the grid is essential.

Paging

When using paging, the GridView/SQLDataSource controls can handle this automatically, meaning you do not have to write a single line of code to sort the data by a specific column or page through index values. However, say the gridview is bound to a form that contains search criteria. Furthermore, a data source control is linked to the parameters in the field, When the search button is clicked, all that is needed is for the grid to rebind because the parameters map to the search form fields. Before you rebind, you should consider resetting the page index to zero for several reasons.

Because the criteria changes, most users like to start over from the beginning; it's a natural behavior because usually the most relevant results are at the beginning, and oftentimes people don't like to feel they've missed something by glossing over a page or two of search results. In addition, the new data results may contain less total pages than the previous one, which could throw an exception.

So when binding, I use a private method, which always reset the paging value to zero as such:

    private void BindGrid ( )

    {

        this.gvwResults.PageIndex = 0;

        this.gvwResults.DataBind ( );

    }


Adding Rows Using the Details View

The DetailsView is a mechanism that can add, delete, or update items in a data source. Oftentimes, applications use a master/details view approach, where the master is the gridview with all the pertinent results, and the details view shows a single item's details, along with providing the ability to insert, update, or delete. These two controls work well together, but there are times when you need to control this interaction programmatically. For instance, the detailsview is usually bound to a gridview selection, which means there have to be items in the data source for the grid view to show data and for the details view to render. However, what if you have no data, and you need to get started inserting items? This information isn't shown immediately.

This is where it is helpful to have a link somewhere on the page, that can trigger the details view to change it's display mode. By default, details view is in read mode. This property can be changed through the ChangeMode method at run time, or through the DefaultMode property at design time. The link button's click event handler can programmatically change the current display mode, so when no records are available, the insert functionality can still be invoked. Even when there is data, to insert an item one must select an entry in the gridview, which isn't the most user-friendly.

    void lnkAddProduct_Click ( object sender, EventArgs e )

    {

        this.dvwProduct.ChangeMode ( DetailsViewMode.Insert );

        this.dvwProduct.DataBind ( );

    }

There are other options as well. Using the AlwaysVisibleControlExtender from the ASP.NET AJAX Control Toolkit (http://ajax.asp.net/ajaxtoolkit/AlwaysVisibleControl/AlwaysVisibleControl.aspx), you can put your administrative links that invoke creating a new row in the details view, or any other option, in a panel that is extended by the control extender. Then, the panel always appears visible, follows you throughout the page, and could be programmatically shown/hidden.

In the next article, I plan to show some of the error-handling aspects of the controls, as well as bring in ASP.NET AJAX into the mix.