May 13

Dynamic data pages: showing lists

Posted in ASP.NET      Comments Off on Dynamic data pages: showing lists

[After talking with my friend JPC, I think I should change the title of these posts After all, aspx pages are DYNAMIC pages!]

During this post, I”ll use the tables I”ve created in the last post about dynamic pages. Today, we”re going to take a  look at the DynamicList control. We”ll start by creating a new dynamic page, called Students.aspx (note that the name of the page is important. it”s used to map the current page to a table maintained in the database), and after dropping a DynamicList control, we”ll have the following:

<%@ Page Language=”C#” CodeFile=”students.aspx.cs” Inherits=”students”%>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “”>
<html xmlns=”” >
  <head runat=”server”>
     <title>Untitled Page</title>
  <form id=”form1″ runat=”server”>
      <asp:DynamicList runat=”server” id=”mylist” />

Opening the page in the browser should show you a grid that shows all the elements that exist in the table. After taking a look at the page, it”s obvious that it needs improvements. Since you”re developing an ASP.NET app, why not use a theme and define the styles that should be applied to the grid by creating a new skin? Yes, you can use that strategy if you”re not using a “named” skin, ie,there”s really no way to apply a named skin to a dynamic control. This poses an interesting question: what must you do if you want to apply a “named” skin? and what if you decide to apply css styles directly to the control instead of using themes and skins? Glad you asked :,) That”s why dynamic controls expose a property called ControlID.

The objective of this property is to let you specify which control  should be used as  a template (well, in fact, it only supports GridView controls) for the rendering of the data that comes from the db (btw, note that all dynamic controls expose this property and you can use this approach if you decide to customize the other dynamic controls which will be presented in the future).

To illustrate its usage, lets say that instead of creating a default skin, we”ve created a skin called red which looks like this:

<asp:GridView skinid=”red” runat=”server” CellPadding=”4″ ForeColor=”#333333″
       <footerstyle backcolor=”#5D7B9D” font-bold=”True” forecolor=”White” />
       <rowstyle backcolor=”#F7F6F3″ forecolor=”#333333″ />
       <pagerstyle backcolor=”#284775″ forecolor=”White” horizontalalign=”Center” />
       <selectedrowstyle backcolor=”#E2DED6″ font-bold=”True” forecolor=”#333333″ />
       <headerstyle backcolor=”#5D7B9D” font-bold=”True” forecolor=”White” />
       <editrowstyle backcolor=”#999999″ />
       <alternatingrowstyle backcolor=”White” forecolor=”#284775″ />

To apply this skin to our page, we must add a new GridView control to the page and set its skin through the SkinID property:

<asp:GridView runat=”server” id=”grid” skinID=”red” />

Then, we only need to set the ControlID property on the DynamicList control:

<asp:DynamicList runat=”server” id=”mylist” controlid=”grid” />

And that”s it!

You might get excited by this and try to define the columns that should be shown by adding them explicitly to the Columns property of the grid GridView. Don”t even waste your time doing that since it won”t work. btw, this is also valid for the other properties related with button generation (ex.: AutoGenerateDeleteButton). This happens because, internally, the dynamic control will take the responsibility of adding the correct fields to the GridView Column collection.

So, what can you do customize the columns shown? Easy: just override the GetColumns method introduced by the DynamicDataPage class. Currently, dynamic controls are deeply integrated with this class (in fact, they can only be used in this type of pages!). So, when you customize the GetColumns method of the page (through an override, if you”re using a strongly typed language), you”re just saying: “hey, please show only these columns”.

For instance, if you decide that you only want to show the Name field, you need to insert this code in your page:

public override IEnumerable GetColumns()
  return new object[] { “Name”};

But there”s more! You can create custom columns by adding DynamicDataColumn objects to the object array that is returned from the GetColumns overide. The following code shows how this can be done:

public override IEnumerable GetColumns()
    return new object[] {
          new DynamicDataColumn( “Complete info”, delegate{
                  return string.Concat( EvalS( “Name” ), ” – “, EvalS( “Address” ) ); } )

The repvious code adds a  DynamicDataColumn object (a new colum) with the title Complete info and a value which is computed dymamicaly – in this case, it simple concatenates the values of each column by using the EvalS method that is introduced in the page by the DynamicDataPage class). Well, after discovering DynamicDataColumn and taking a peek at its constructors,  I thought that it could be used to define the title of a column. In fact, it really looks like it should be used for this. Unfortunately, doing something like this does not work:

public override IEnumerable GetColumns()
    return new object[] {
          new DynamicDataColumn( “Std. Name”, “Name” ), //DOESN”T WORK!
          new DynamicDataColumn( “Complete info”, delegate{
                  return string.Concat( EvalS( “Name” ), ” – “, EvalS( “Address” ) ); } )

But not all is lost. Remember: we”ve added a grid to the page and associated it with the DynamicList control. This means we can handle the RowCreated event that will be fired by the grid during the creation of each row. After setting the grid on the aspx page:

<asp:GridView runat=”server” id=”grid” skinID=”red”
  Onrowcreated=”HandleRowCreated”  />

You just need to add the code to the codebehind page:

protected void HandleRowCreated( object sender, GridViewRowEventArgs e )
    if (e.Row.RowType == DataControlRowType.Header )
       e.Row.Cells[1].Text = “Std. Name”;

If you only need to customize the data rows presented by the control, then there”s another method exposed by the page that will let you do just that: the InitRow
method (note that this method will be called in response to the RowCreated  event, but you”ll only receive references to data rows – which means that the previous code won”t work if you put it in this method). Here”s some code that changes the color of the 1st row to red:

public override void InitRow(GridViewRow row)
   if (row.RowIndex == 0)
        row.BackColor = Color.Red;

Overriding that method won”t help you if you need to customize the data shown to the user (the row data bound event is fired after the row created event). In those cases, you should use DynamicColumns or handle the RowDataBound event fired by the grid. Sometimes, this last option is your best bet. For instance, here”s some code that handles the event of the “template” grid (that has been added to the page and associated with the control) and that  changes the background of the row for all the studends that have a name with more than 3 chars:

protected void HandleRowDatabound(object sender, GridViewRowEventArgs e)
   if (e.Row.RowType == DataControlRowType.DataRow)
    if (e.Row.Cells[1].Text.Length > 3)
        e.Row.BackColor = Color.Red;

Before ending this long post, there”s still time to present a couple of properties exposed by the DyamicList control. Currently, you can enable/disable the edit and delete buttons through the use of the EnableDelete and EnableUpdate properties. There”s still one more property worth mentioning: the UIControl property. This property returns a reference to the inner grid used by the control to present data. It”s important to keep in mind that this property is initialized during the Init event (thanks Reflector 🙂 ), so there are some things which you can”t do without using an associated grid on the page (ex.: setting a named skin). You can, however, hook up event handlers that might help you perform some actions like the ones presented earlier.

And that”s all for today!