OK.. phew. Playing with data grids for the past few days has been fun and a
huge learning experience..
My problem. I have a requirement to display a gird with a gird. Within the
embedded grid, theres a requirement to show a drop down menu list (this is a
control I downloaded online) in one of the columns. For the purposes of this
question, Ive implemented the drop down menu as a drop down list instead.
Ive got all this working at this point. Heres my problem:
1) When a person selects an item in the drop down list, I need the server to
autopost back and fire an event which I can handle on the sever side.
2) On the server side, I need to be able to figure out which drop down list
the event was fired for and what the selected value is.
Ive implemented the display of the column showing the drop down list in a
custom built DataGridColumn. All the code is below.
My Question:
1) How do I setup ONE postback event handler for ALL the drop downlist
controls being rendered dynamically in the embedded grid?
2) The event handler must be in the code-behind code that uses the custom
built DataGridColumn and should not be in the DataGridColumn code itself.
2) How do I figure out in that one event handler method, the drop down list
that threw the event, and the value of the selected item.
If you look towards the end of the method
CustomerDataGrid_OnItemDataBound(object sender, DataGridItemEventArgs e),
you'll find the code where I programmatically attach the new column. The
custom col code itself is the last snippet of code in this email.
Appreciate anyones help.
Girish
----------------
ASPX CODE
---------------
<%@ Page language="c#" Inherits="MasterDetail.CustomerOrderDataGrid"
EnableViewState="False" CodeBehind="CustomerOrderDataGrid.aspx.cs"
AutoEventWireup="false" %>
<HTML>
<LINK REL=StyleSheet HREF="menu.css" TYPE="text/css" />
<body style="FONT: x-small Verdana, Arial, sans-serif">
<!-- Begin Web Form -->
<form id="CustomerOrderDataGrid" method="post" runat="server">
<p><a href="/DayOfDotNet/">Parent Directory</a></p>
<!-- Begin DataGrid -->
<asp:DataGrid id="CustomerDataGrid" runat="server"
AutoGenerateColumns="False" CellPadding="2"
CellSpacing="0" Font-Names="Verdana, Arial, sans-serif"
BorderColor="Black" BorderWidth="1"
GridLines="Horizontal"
OnItemDataBound="CustomerDataGrid_OnItemDataBound" EnableViewState="False">
<AlternatingItemStyle BackColor="Tan"></AlternatingItemStyle>
<ItemStyle Font-Size="X-Small"></ItemStyle>
<HeaderStyle Font-Size="Small" Font-Names="Arial" Font-Bold="True"
ForeColor="White" BackColor="Maroon"></HeaderStyle>
<Columns>
<asp:BoundColumn Visible="False"
DataField="CustomerID"></asp:BoundColumn>
<asp:HyperLinkColumn
DataTextField="CustomerID"
DataNavigateUrlField="CustomerID"
DataNavigateUrlFormatString="OrderDetailDataGrid.aspx?customerid={0}"
HeaderText="ID"
ItemStyle-VerticalAlign="Top" />
<asp:TemplateColumn HeaderText="Customer">
<ItemStyle VerticalAlign="Top"></ItemStyle>
<ItemTemplate>
<b>
<%# DataBinder.Eval(Container.DataItem, "CompanyName") %>
</b>
<br>
<%# DataBinder.Eval(Container.DataItem, "Address" ) %>
<br>
<%# DataBinder.Eval(Container.DataItem, "City" ) %>
,
<%# DataBinder.Eval(Container.DataItem, "Region") %>
<%# DataBinder.Eval(Container.DataItem, "PostalCode" ) %>
<br>
<br>
<%# DataBinder.Eval(Container.DataItem, "ContactName" ) %>
<br>
<%# DataBinder.Eval(Container.DataItem, "ContactTitle" ) %>
<br>
<%# DataBinder.Eval(Container.DataItem, "Phone" ) %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn ItemStyle-VerticalAlign="Top"
HeaderText="Orders">
<%-- Embedded DataGrid will go here --%>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
<!-- End DataGrid -->
</form>
<!-- End Web Form -->
</body>
</HTML>
-------------------
CODE BEHIND
------------------
using System;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Configuration;
namespace MasterDetail
{
public class CustomerOrderDataGrid : System.Web.UI.Page
{
protected DataGrid CustomerDataGrid;
private DataSet ds = new DataSet();
private void Page_Load(object sender, System.EventArgs e)
{
string sqlStmt = "SELECT top 2 * FROM Customers; SELECT * FROM Orders";
string conString =
"server=localhost;database=Northwind;uid=sa;pwd=tietronix;";
SqlDataAdapter sda = new SqlDataAdapter(sqlStmt, conString);
sda.Fill(ds);
ds.Tables[0].TableName = "Customers";
ds.Tables[1].TableName = "Orders";
CustomerDataGrid.DataSource = ds.Tables["Customers"];
CustomerDataGrid.DataBind();
}
//Use the OnItemDataBound event handler to dynamically add an embedded
DataGrid
protected void CustomerDataGrid_OnItemDataBound(object sender,
DataGridItemEventArgs e)
{
//When each row is created in the DataGrid, eval the ItemType
if(e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
//If the ItemType is Item or AlternatingItem,
//Create a new DataGrid object named OrdersDataGrid
DataGrid OrdersDataGrid = new DataGrid();
//Format the DataGrid to look cool.
OrdersDataGrid.BorderWidth = (Unit)1;
OrdersDataGrid.CellPadding = 4;
OrdersDataGrid.CellSpacing = 0;
OrdersDataGrid.GridLines = GridLines.Horizontal;
OrdersDataGrid.BorderColor = Color.FromName("Black");
OrdersDataGrid.ItemStyle.Font.Name = "Verdana";
OrdersDataGrid.ItemStyle.Font.Size = FontUnit.XSmall;
OrdersDataGrid.AlternatingItemStyle.BackColor =
Color.FromName("LightGray");
OrdersDataGrid.ShowHeader = true;
OrdersDataGrid.HeaderStyle.BackColor = Color.FromName("Black");
OrdersDataGrid.HeaderStyle.ForeColor = Color.FromName("White");
OrdersDataGrid.HeaderStyle.Font.Bold = true;
OrdersDataGrid.HeaderStyle.Font.Size = FontUnit.XSmall;
//Do not autogenerate columns.
OrdersDataGrid.AutoGenerateColumns = false;
//Add a series of BoundColumns
//Order ID
BoundColumn bc = new BoundColumn();
//Set the BoundColumn Values
bc.HeaderText = "Order ID";
bc.DataField = "OrderID";
bc.ItemStyle.Wrap = false;
//Add the BoundColumn to the OrdersDataGrid.
OrdersDataGrid.Columns.Add(bc);
//Order Date
bc = new BoundColumn();
bc.HeaderText = "Order Date";
bc.DataField = "OrderDate";
bc.DataFormatString="{0:d}";
bc.ItemStyle.Wrap = false;
OrdersDataGrid.Columns.Add(bc);
//Required Date
bc = new BoundColumn();
bc.HeaderText = "Required Date";
bc.DataField = "RequiredDate";
bc.DataFormatString="{0:d}";
bc.ItemStyle.Wrap = false;
OrdersDataGrid.Columns.Add(bc);
//Shipped Date
bc = new BoundColumn();
bc.HeaderText = "Shipped Date";
bc.DataField = "ShippedDate";
bc.DataFormatString="{0:d}";
bc.ItemStyle.Wrap = false;
OrdersDataGrid.Columns.Add(bc);
// ADD THE CUSTOM BUILT COL HERE
DropDownListColumn DDLC = new DropDownListColumn();
DDLC.HeaderText = "My DDL";
OrdersDataGrid.Columns.Add(DDLC);
//End BoundColumns
//Get the Authors DataView and filter it for the current ISBN
DataView _orders = ds.Tables["Orders"].DefaultView;
_orders.RowFilter = "CustomerID='" + e.Item.Cells[0].Text + "'";
//Bind the DataGrid.
OrdersDataGrid.DataSource = _orders;
OrdersDataGrid.DataBind();
e.Item.Cells[3].Controls.Add(OrdersDataGrid);
}
}
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
}
}
----------------------------------
Custom built data Grid col code
-----------------------------------
using System;
using System.Web.UI.WebControls;
namespace MasterDetail
{
public class DropDownListColumn : DataGridColumn
{
public DropDownListColumn() : base()
{
}
public override void InitializeCell(TableCell cell, int columnIndex,
ListItemType itemType)
{
base.InitializeCell(cell, columnIndex, itemType);
switch (itemType)
{
case ListItemType.EditItem:
case ListItemType.Item:
case ListItemType.AlternatingItem:
case ListItemType.SelectedItem:
cell.DataBinding += new EventHandler(this.ItemDataBinding);
DropDownList DLL = new DropDownList();
cell.Controls.Add( DLL );
break;
case ListItemType.Header:
break;
}
}
private void ItemDataBinding(object sender, EventArgs e)
{
TableCell cell = (TableCell)sender;
DropDownList DDL1 = (DropDownList)cell.Controls[0];
DDL1.Items.Add(new ListItem("one","1"));
DDL1.Items.Add(new ListItem("two","2"));
DDL1.Items.Add(new ListItem("three","3"));
}
}
}
Phillip Williams - 19 Jul 2005 14:35 GMT
> My Question:
>
[quoted text clipped - 4 lines]
> 2) How do I figure out in that one event handler method, the drop down list
> that threw the event, and the value of the selected item.
You can have the dropdownlist raise the SelectedIndexChanged event and then
trap the event (in the codebehind of the Page class, as you wanted) using
Event Bubbling. Lookup for samples on Event Bubbling on the MSDN library.
Consider though the size of the downloaded page. If every row of your
DataGrid were to repeat the same data for the dropdownlist then your page can
easily run over 1 megabyte in size (when handling real data). I would either:
1. Add an EditCommandButton in the DataGrid and leave the DropDownList in
the EditItemTemplate of one column. The DropDownList will only be displayed
in one row at a time when you bind it to its DataSource (this happens during
your handling the EditItem event). In this scenario the Update button would
raise the ItemCommand event. In processing the ItemCommand event you can get
both:
a. The ItemIndex of the grid where the postback occurred:
e.Item.ItemIndex, and
b. A reference to the dropdown list:
(DropDownList)e.Item.Cells[x].Controls[0]
(where x = the column no).
2. Replace the DropDownList by a TextBox and use client-side Javascript
to transform an xml data document using xslt to display a list of matching
results as demonstrated on this page:
http://www.societopia.net/samples/textbox.htm

Signature
http://www.webswapp.com
http://www.societopia.net
Girish - 19 Jul 2005 23:30 GMT
Appreciate the insight into page load size. I dont think this will be an
issue since we will be working with barely 10 rows per page.
I looked at Event Bubbling, but it requires that my DropDownListColumn
inherit from class Control. My DropDownListColumn already inherits from
DataGridColumn so i cant multiple inherit... im sure im missing something
simple here. pse advice.
thanks,
Girish
>> My Question:
>>
[quoted text clipped - 40 lines]
> results as demonstrated on this page:
> http://www.societopia.net/samples/textbox.htm
Phillip Williams - 20 Jul 2005 04:07 GMT
This is a quick modification of your code to make the Event Bubbling works
http://www.societopia.net/samples/webform6.aspx
If I had more time I could have probably created a more elaborate custom
event.
I would still prefer the EditItem Template strategy as I mentioned in the
previous email. It is much cleaner.
Phillip

Signature
http://www.webswapp.com
> Appreciate the insight into page load size. I dont think this will be an
> issue since we will be working with barely 10 rows per page.
[quoted text clipped - 51 lines]
> > results as demonstrated on this page:
> > http://www.societopia.net/samples/textbox.htm
girish - 20 Jul 2005 04:35 GMT
Thanks for your help again Phillip. I tend to be very inquisitive by
nature... my apologies in advance.. :)
1) What do you mean by "create a more elaborate custom event?" :)
2) To bubble events in user created controls, you have to inherit from
control and override RaiseBubbleEvent . Why is this? Why cant you get away
with what you did in your example?
If you could point me to articles, that would also be helpful rather than
typing out huge replies. :)
Thanks a mill again,
Girish
> This is a quick modification of your code to make the Event Bubbling works
> http://www.societopia.net/samples/webform6.aspx
[quoted text clipped - 70 lines]
>> > results as demonstrated on this page:
>> > http://www.societopia.net/samples/textbox.htm
Phillip Williams - 20 Jul 2005 05:35 GMT
> Thanks for your help again Phillip. I tend to be very inquisitive by
> nature... my apologies in advance.. :)
You are welcome. I get to learn too.
> 1) What do you mean by "create a more elaborate custom event?" :)
In this example I had to pass the primary key of the record as the ID of the
dropdownlist control to discover the GridDataItem.ItemIndex. There might be a
better way of doing that.
> 2) To bubble events in user created controls, you have to inherit from
> control and override RaiseBubbleEvent . Why is this? Why cant you get away
> with what you did in your example?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cp
conbubblingcommandevent.asp
In this sample you had your parent Grid on the webform already and added the
code for the child grid in the same page of the codeBehind. This is a just a
proof of concept. However if you intend to deploy them in production you
might create each as separate control inherited from the datagrid and have to
bubble events from the child grid to the parent and then from the parent to
the page that contain it or any other container that you have customized.
Phillip
---
www.societopia.net
www.webswapp.com
Phillip Williams - 21 Jul 2005 21:04 GMT
> Thanks for your help again Phillip. I tend to be very inquisitive by
> nature... my apologies in advance.. :)
>
> 1) What do you mean by "create a more elaborate custom event?" :)
I found a couple of nice and clear samples on the MSDN library to help you
create event delegates and custom event data classes that you might be
interested in:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cp
coneventsmini-sample.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cp
concompositecontrolsample.asp
Hope this helps.
Phillip
---
http://www.webswapp.com
http://www.societopia.net
Girish - 21 Jul 2005 22:15 GMT
Thanks Phillip. :) Youve been a great help.
g
>> Thanks for your help again Phillip. I tend to be very inquisitive by
>> nature... my apologies in advance.. :)
[quoted text clipped - 15 lines]
> http://www.webswapp.com
> http://www.societopia.net