Handling DataGrid row events
When creating user interface the common situation is to handle datagrid row event in response to user action. Example of that is changing dropdown list value and refreshing row information without reloading the whole datagrid.
For instance if we have a datagrid with the products containing dropdown list with the clients in each row, we can allow the user to change datagrid row data separately without resetting other datagrid rows.
In our example we will build the simple datagrid with the products that will allow us to select and send voucher codes to the clients with total purchase exceeding certain level in product category.
Lets start with creating basic class structures:
public class Client { public Client(){} public int ID { get; set; } public string Name { get; set; } public IList<Product> Products { get; set; } } public class Product { public Product() { } public int ID { get; set; } public int CatID { get; set; } public string Name { get; set; } public double Price { get; set; } }
After creating new asp.net website project with default.aspx page, we need to add some dummy data in page load event (to be replaced with the database data). We cerate product list and assign product categories to it. And finally create client list and assign products they bought.
We use LINQ to quickly load products to client objects “p => p.Price > 10” – this will load products with the price greater than 10.
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { #region mock data productList.Clear(); clientList.Clear(); productList.Add(new Product() { ID = 1, CatID = 1, Name = "product1", Price = 22 }); productList.Add(new Product() { ID = 2, CatID = 3, Name = "product2", Price = 32 }); productList.Add(new Product() { ID = 3, CatID = 1, Name = "product3", Price = 42 }); productList.Add(new Product() { ID = 4, CatID = 3, Name = "product4", Price = 62 }); productList.Add(new Product() { ID = 5, CatID = 2, Name = "product5", Price = 12 }); productList.Add(new Product() { ID = 6, CatID = 2, Name = "product6", Price = 62 }); productList.Add(new Product() { ID = 7, CatID = 4, Name = "product7", Price = 82 }); productList.Add(new Product() { ID = 8, CatID = 4, Name = "product8", Price = 22 }); clientList.Add(new Client() { ID = 1, Name = "client1", Products = productList.Where(p => p.Price > 10).ToList() }); clientList.Add(new Client() { ID = 2, Name = "client2", Products = productList.Where(p => p.Price > 30).ToList() }); clientList.Add(new Client() { ID = 3, Name = "client3", Products = productList.Where(p => p.Price > 60).ToList() }); clientList.Add(new Client() { ID = 4, Name = "client4", Products = productList.Where(p => p.Price > 80).ToList() }); clientList.Add(new Client() { ID = 5, Name = "client5", Products = productList.Where(p => p.Price > 40).ToList() }); #endregion /////////////// gridList.DataSource = productList; gridList.DataBind(); } }
Once we have data loaded into our datagrid, we need to create client lists in each row. We will do it in gridList_RowDataBound event. What we do is simply finding the dropdown list in each row and bind the client list to it.
When binding dropdown lists we use custom object created on the fly using LINQ – see my previous articles to get description of that process.
protected void gridList_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e) { if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow) { var ddlClients = e.Row.FindControl("ddlClients") as DropDownList; ddlClients.DataSource = (from obj in clientList select new { ID = obj.ID, Name = string.Format("{0} [prod. {1}]", obj.Name, obj.Products.Count()) }).ToList().OrderByDescending(a => a.Name).ThenBy(a => a.ID); ddlClients.DataTextField = "Name"; ddlClients.DataValueField = "ID"; ddlClients.DataBind(); RenderGridRow(e.Row); } }
Our next step is to create selected index changed event for the client lists in the datagrid. Every time someone will change the client, the corresponding datagrid row will be updated.
protected void dropdownlist_SelectedIndexChanged(object sender, EventArgs e) { GridViewRow gridRow = (GridViewRow)(((System.Web.UI.Control)sender).NamingContainer); gridList.SelectedIndex = gridRow.RowIndex;// highlight the current the row RenderGridRow(gridRow); }
In our case we will render datagrid row as follows:
void RenderGridRow(GridViewRow row) { var catID = (row.FindControl("ctrlCatID") as HiddenField).Value; var ddlClients = row.FindControl("ddlClients") as DropDownList; var ltrTotal = row.FindControl("ltrTotal") as Literal; var btnSendVoucher = row.FindControl("btnSendVoucher") as Button; /////////////////// btnSendVoucher.CommandArgument = ddlClients.SelectedItem.Value.ToString();// we use it as alternative var items = clientList.Find(e => e.ID.ToString() == ddlClients.SelectedItem.Value.ToString()) .Products.Where(p => p.CatID.ToString() == catID.ToString()); var total = items.Any() ? items.Sum(p => p.Price) : 0; ltrTotal.Text = total > 0 ? total.ToString("C") : "no products bought in this category"; }
The final step is to handle send voucher button event:
protected void btnSendVoucher_OnClick(object sender, EventArgs e) { GridViewRow gridRow = (GridViewRow)(((System.Web.UI.Control)sender).NamingContainer); //or use //var clientID = ((Button)sender).CommandArgument; var txtVoucher = gridRow.FindControl("txtVoucher") as TextBox; var ddlClients = gridRow.FindControl("ddlClients") as DropDownList; var clientID = ddlClients.SelectedItem.Value.ToString(); var voucher = txtVoucher.Text; //send voucher to client here }
That’s it. I have attached working example below. Feel free to play with it 🙂
gridViewEvent