Library tutorials & articles

Web Forms DataGrid and DataSet Programming

General Concepts

In this project, the DataSet and a View is filled on every page load with a call to:

sqlDataAdapter1.Fill(dataSet11);
view = dataSet11.Tables[0].DefaultView;

The DataGrid is only refreshed from the View/DataSet on the first page load (or in the appropriate event handler):

if (!IsPostBack)
{
...
DataGrid1.DataBind();
}

If you do not call DataBind(), the DataGrid state is refreshed from the ViewState. This is accomplished by DataGrid's automatic support for persistence on post back (enableViewState= true).

Persisting the DataSet

An alternate solution to hitting the database on ever page load, is to persist the DataSet to ViewState or to the Session object, calling Update() only when the user is ready to commit all changes. As a result of .NET's built in support for Optimistic Concurrency, the update could fail if another user has edited or deleted a row of interest since the initial page load. If you implement this solution, you would need to add a "commit" button to save changes and a "refresh" button to allow the user to reload the DataSet.

Default Paging Loads The Entire DataSet

It is important to understand that much of the simplicity and power of default paging and sorting is greatly simplified by loading the entire DataSet into memory. However, this may not be a very efficient use of server memory. One solution is to limit the amount of data returned from the database by implementing "custom paging", returning only the current page of rows to the dataset. For a very large data set (Customers-Orders-OrderDetails) it may be more efficient to return a single row at a time using "custom paging" with a page size of one! In this scenario, the user navigates through a hierarchy of virtual tables of Customers and Orders, displaying only the OrderDetails in a DataGrid.

DataGrid State Is Persisted By Default

In a similar manner, the DataGrid comes with built in support for data persistence. By default, the EnableViewState property is set to true so that the data is written to a hidden field in the HTML output. This data is then sent back to the server on post back and is used to refresh the DataGrid . Loading the entire "Customer" table into a DataGrid is inefficient. One solution is to use paging to limit the amount of data that must be persisted in ViewState.

Invalid Page Index and Unintended Editing Bugs

Two rather obscure bugs can creep into your program when you enable paging. One is trying to page to an invalid page. On a single user system, this occurs when the user deletes the only row on the last page. When you call DataBind(), the page index is persisted and an attempt is made to page the data set, throwing an exception. However, a much more subtle bug occurs when _another_ user deletes one or more rows. For this reason, you need to check for an invalid page index on every call to DataBind after the initial page load. If you persist the DataSet to ViewState or Session state, you only need to check for an invalid index when the user refreshes the DataSet or deletes a row. Here is our ResetPageIndex function:

// ResetPageIndex resets invalid page index to last page
// ASSERT grid and view NOT NULL
protected void ResetPageIndex(DataGrid grid, DataView view)
{
    // check for invalid page index
    if ((grid.CurrentPageIndex != 0) && (((grid.CurrentPageIndex)*grid.PageSize)>= view.Count))
    {
        // invalid so leave at last page
        if ((view.Count % grid.PageSize)== 0)
        { // ends on page border
            grid.CurrentPageIndex= (view.Count/grid.PageSize)-1;
        }
        else // partial page
        {
            grid.CurrentPageIndex= (view.Count/grid.PageSize);
        }
    }
}

Another subtle bug is seen when the user is in the edit mode and pages to another page. If you don't reset the edit index, the user is left unexpectedly in edit mode on the new page.

Saving Variable State

Since the web is by nature stateless, changes to a instance variable are lost on post back. To implement "state", you must manually write the value of the variable to the ViewState object and then read the saved value of the variable from the ViewState on post back. Here is some sample code from the PageLoad function that demonstrates how to save the sort order and sort column values:

// This code executes the first time only
if (!IsPostBack)
{
  view.Sort = "au_id"+ " ASC";
  ViewState["LastSortOrder"]="ASC";
  ViewState["LastSortColumn"]= "au_id";
  ViewState["LastFilter"]= "";
  DataGrid1.DataBind();
}
else // This code executes only on post back
{
  string lastSortColumn= (string)ViewState["LastSortColumn"];
  string lastSortOrder= (string)ViewState["LastSortOrder"];
  string lastFilter= (string)ViewState["LastFilter"];
  view.Sort= lastSortColumn+ " "+ lastSortOrder;
  view.RowFilter= lastFilter;
}

Saving the DataSet and Concurrency Control

In this sample project the dataset is refreshed on every page load, effectively negating .NET's built in support for optimistic concurrency. The UPDATE method of the SqlAdapter uses the original values of the DataSet to implement optimistic concurrency by looking for the original unaltered record in the database. The DataSet stores these original values in memory, but you must persist the dataset between page loads or the original data will be lost. It is possible to persist the dataset using the ViewState or Session object on the first page load. This will persist the original values on post back. Persisting the DataSet into ViewState or into the Session object, allows .NET's optimistic concurrency control to work properly.

Using Code Behind

This project was created with the IDE project wizard. As such, it uses "code behind". The HTML layout (WebForm1.aspx) is separated from the application logic which resides in the WebForm1.aspx.cs file. If you look at the WebForm1.aspx file in the HTML view you can see where the code behind is declared:

Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="WebApplication3.WebForm1"
trace="false"

The project includes the following files (not inclusive):

  • WebForm1.aspx
  • WebForm1.aspx.cs
  • DataSet1.xsd

WebForm1.aspx

It is important to understand that the WebForm1.aspx file can be viewed in both Design and HTML views. You may need to edit or at least look at the IDE code in the HTML view to understand how events are wired. For example, here is the HTML code that is used to not only create the DataGrid, but also to wire the event handlers. Note that clicking on the "delete" link will call the DataGrid1_Delete function: OnDeleteCommand="DataGrid1_Delete"

<asp:datagrid id=DataGrid1 style="Z-INDEX: 101; LEFT: 23px; POSITION: absolute; TOP: 221px" runat="server" DataKeyField="au_id" DataSource="<%# view %>" Height="270px" Width="679px" OnUpdateCommand="DataGrid1_Update" OnCancelCommand="DataGrid1_Cancel" OnEditCommand="DataGrid1_Edit" OnDeleteCommand="DataGrid1_Delete" BorderColor="Blue" OnItemCommand="Item_Click" AllowSorting="True" OnSortCommand="DataGrid1_Sort" AllowPaging="True" OnPageIndexChanged="DataGrid1_Page" BackColor="#C0FFFF">

WebForm1.aspx.cs

The file WebForm1.aspx.cs contains the C# code behind. To create a button event handler I simply double clicked on the "Add", "Clear" and "Filter" buttons in the design view. The wizard created the empty event handler functions and registered the functions with the buttons. Note that the wizard generated code is hidden by default. You can expand the hidden code and look at the wizard's source code to see how the button event handlers were registered:

this.buttonFilter.Click += new System.EventHandler(this.buttonFilter_Click);
this.buttonAdd.Click += new System.EventHandler(this.buttonAdd_Click);
this.buttonClear.Click += new System.EventHandler(this.buttonClear_Click);

DataSet1.xsd

The XML schema can be viewed in the DataSet1.xsd file. Note that the schema can be viewed as a "DataSet" table or as raw XML. This view can also be used to view and create more complex master-detail hierarchies.

Comments

  1. 26 Jan 2006 at 14:50
    How could i do all this with untyped dataset from xml source? (no find methods etc..)
    Vjero
  2. 23 Nov 2005 at 14:26

    hi
    hey ppl i m   inserting some data manually in a dataview then i m sorting that dta via dataview.sort , sorting is taking place perfectly here but when i embed this data into a word document  then  i found that data is not  in sorted order as this supposed to be but it is in order in which it had typed...........so guys if u  have have any solution of this problem  then plz  mail me at aman_105@rediffmail.com

  3. 10 Nov 2005 at 09:33

    hello
     I am converting C#.net code into vb.net code .
     Sorting ASC or DESC  is not working .
     while degugging ,code work fine but i think some how dataset is not getting refreshed.
     I have commented these line  'view.RowFilter = lastFilter' .Is it require for sorting
     Execpt that everything is same
      please help me out .
                                                Thanks            
     

  4. 30 Jun 2005 at 02:13

    Hi.


    I dont know if this only a problem of mine, but when I hit a sort column the DataGridSortCommand happens twice.


    Should this happen? In my case it happens and so all the code in that event doesnt work properly...


    Could some help me out on this one?


    TIA,
    C.C.

  5. 10 Nov 2004 at 09:24
    How do I obtain ResetPageIndex? It is unknown to my installation of .NET or at least to the libraries I am using.
  6. 01 May 2004 at 12:13

    Jeff,


    Thanks a bunch!  I am new to ASP.NET programming and it was having a devil of a time getting my datagrid to sort -- your example provided the one missing link: the DataSource property should have been set to the view and not the dataset! Tanx again.


    --Babak

  7. 01 Jan 1999 at 00:00

    This thread is for discussions of Web Forms DataGrid and DataSet Programming.

Leave a comment

Sign in or Join us (it's free).

Jeff Louie

Related podcasts

Events coming up

  • Mar 15

    DevWeek 2010

    London, United Kingdom

    DevWeek is Europe’s leading independent conference for software developers, database professionals and IT architects, and features expert speakers on a wide range of topics, including .NET 4.0, Silverlight 3, WCF 4, Visual Studio 2010, REST, Windows Workflow 4, Thread Synchronization, ASP.NET 4.0, SQL Server 2008 R2, LINQ, Unit Testing, CLR & C# 4.0, .NET Patterns, WPF 4, F#, Windows Azure, ADO.NET, Entity Framework, Debugging, T-SQL Tips & Tricks, and more.

Want to stay in touch with what's going on? Follow us on twitter!