Wednesday, February 13, 2008

Fun with DataGrids

Copyright © 2008, Steven E. Houchin

Recently, I was implementing a DataGrid for an ASP.NET application. ASP.NET is not usually my forte, so I was once again in learning mode.

The first obstacle I stumbled onto was that a lot more columns were displayed when the page came up than what I intended. My DataSource was an ArrayList of objects, which represented information culled from the database. In the page's Page_Load function, I had code that created each column explicitly, using ButtonColumn and BoundColumn objects. The extraneous unwanted columns that displayed were duplicates of the DataSource object's properties.

I discovered the problem was with the AutoGenerateColumns property of the DataGrid. Its default value was True, which causes a DataGrid object to automatically create columns (duh!) identical to the DataSource object's properties ... just what I was seeing. Setting this to False prior to assigning the DataSource value fixed that.

The next obstacle was that my ItemCommand handler wouldn't fire when I clicked on a ButtonColumn item in the list. Worse, my grid completely disappeared afterward. Searching around on the web revealed many others who also had this problem, but nobody seemed to have a good answer. There were some postings about EnableViewState related to this, but they didn't help.

Eventually, I discovered that when the Click event caused a PostBack to the page, the DataGrid reverted back to its initial empty state. My Page_Load code populated the DataGrid only when the call was not a PostBack. Armed with this insight, I changed Page_Load so a PostBack call only decides where to get the data: a database call for non-PostBack versus session variable on PostBack. The code now creates and binds the DataGrid columns each time through Page_Load, since my columns are created on-the-fly. The fixed code follows:



ArrayList allUsers = null;
if (IsPostBack)
{
   // restore array of all users
   allUsers = controller.GenericPageData as ArrayList;
}
else
{
      // get an array of all users as UserProfile objects
      controller.Model_GetAllUserInfo(ref allUsers);

      // save the user data in the controller
      controller.GenericPageData = allUsers as object;
}

if (null != allUsers)
{
   // set the array of users as the data source
   dgUsers.AutoGenerateColumns = false;
   dgUsers.DataSource = allUsers;

   // configure the columns
   ButtonColumn colName = new ButtonColumn();
   colName.DataTextField = "FullName";
   colName.HeaderStyle.BorderStyle = BorderStyle.Outset;
   colName.HeaderStyle.BackColor = Color.Ivory;
   colName.HeaderText = "Full Name";
   colName.CommandName = "View";

   BoundColumn colLogin = new BoundColumn();
   colLogin.DataField = "LoginName";
   colLogin.HeaderText = "Login Name";
   colLogin.HeaderStyle.BorderStyle = BorderStyle.Outset;
   colLogin.HeaderStyle.BackColor = Color.Ivory;

   BoundColumn colId = new BoundColumn();
   colId.DataField = "KeyId";
   colId.HeaderText = "Record Id";
   colId.HeaderStyle.BorderStyle = BorderStyle.Outset;
   colId.HeaderStyle.BackColor = Color.Ivory;

   // add the columns to the datagrid
   dgUsers.Columns.Add(colId);
   dgUsers.Columns.Add(colName);
   dgUsers.Columns.Add(colLogin);

   dgUsers.EnableViewState = false;
   dgUsers.DataKeyField = colId.DataField;
   dgUsers.DataBind();

   // set up the click and edit event callbacks
   dgUsers.ItemCommand +=
      new DataGridCommandEventHandler(this.UsersGrid_OnClick);
   return;
}

No comments: