Jul 13 2007

ASP.NET Repeater control instead of grid

Posted by admin under Controls

If you have read some of my articles here at ASPCode.net by now I am sure you know my strive for doing things myself instead of relying on thirdparty controls. For example, I have developed professional ASP.NET solutions almost every day for at least 5 years and still havn't delivered a single one (well maybe one or two in the beginning) using the datagrid/gridview. I basically think there is a danger of configuration instead of code.

So here's classic repeater control sample (using Northwind products table):

 

and while using a repeater instead of a datagrid also will give us the flexibility to use whatever HTML markup we want (maybe tableless using divs) but for simplicity I have decided to go for plain table:



    <asp:Repeater ID="rep1" runat="server" OnItemDataBound="rep1_ItemDataBound" OnItemCommand="rep1_ItemCommand">
    <HeaderTemplate>
    <table>
    </HeaderTemplate>
    <ItemTemplate>
    <tr>
    <td>
        <asp:Literal ID="litname" runat="server"></asp:Literal>
    </td>
    <td>
        <asp:TextBox ID="txtUnitsInStock" runat="server"></asp:TextBox>
    </td>
    <td>
        <asp:Button ID="btnChangeUnitsInStock" runat="server" Text="Update" />
        <asp:Button ID="btnDiscontinued" runat="server" Text="Set as discontinued" />
    </td>
    </tr>
    </ItemTemplate>
    <FooterTemplate>
    </table>
    </FooterTemplate>
    </asp:Repeater>



 

The codebehind looks like this:



        string sConn = "Data Source=(local);Network Library=DBMSSOCN;Initial Catalog=Northwind;User ID=sa;Password=stefan;";

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                rep1.DataSource = Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteDataset(
                    sConn, CommandType.Text, "select * from products").Tables[0].Rows;
                rep1.DataBind();

            }
        }

        protected void rep1_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                DataRow row = e.Item.DataItem as DataRow;
                Literal litname = e.Item.FindControl("litname") as Literal;
                litname.Text = row["productname"].ToString();
                TextBox txtUnitsInStock = e.Item.FindControl("txtUnitsInStock") as TextBox;
                txtUnitsInStock.Text = row["unitsinstock"].ToString();
...
...




Not hard at all. Now we do need to wire some event handlers to be called when clicking on the buttons. The "hard" part is linking them to the current row. I.e when clicking on Update for "Northwoods Cranberry Sauce" we want that record to be updated not "Aniseed Syrup" or whatever row.

By using the repeaters builtin "command" magic we can do that in just a few lines:



        protected void rep1_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                DataRow row = e.Item.DataItem as DataRow;
                Literal litname = e.Item.FindControl("litname") as Literal;
                litname.Text = row["productname"].ToString();
                TextBox txtUnitsInStock = e.Item.FindControl("txtUnitsInStock") as TextBox;
                txtUnitsInStock.Text = row["unitsinstock"].ToString();

                Button btnChangeUnitsInStock = e.Item.FindControl("btnChangeUnitsInStock") as Button;
                btnChangeUnitsInStock.CommandName = "ChangeUnits";
                btnChangeUnitsInStock.CommandArgument = row["productid"].ToString();

                Button btnDiscontinued = e.Item.FindControl("btnDiscontinued") as Button;
                btnDiscontinued.CommandName = "Discontinued";
                btnDiscontinued.CommandArgument = row["productid"].ToString();


            }
        }





and here's how we handle it (inside the ItemCommand handler)



        protected void rep1_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            if (e.CommandName == "ChangeUnits")
            {
                long lProductId = Convert.ToInt32(e.CommandArgument);
                TextBox txtUnitsInStock = e.Item.FindControl("txtUnitsInStock") as TextBox;
                long lNewCount = Convert.ToInt32(txtUnitsInStock.Text);
                //Call sp or whatever to set unitsinstock to lNewCount for product id lProductId
            }
            if (e.CommandName == "Discontinued")
            {
                long lProductId = Convert.ToInt32(e.CommandArgument);
                //Call sp or whatever to set discontinued for productid lProductId
            }
        }




Herein lies a lot of the power that makes the datagrid/gridview look so nice and easy to use. I.e tying handlers to a specific row. But by being able to apply it to a repeater means we have a lot of other possiblities as well. I will get into that more in a future article.

kick it on DotNetKicks.com