Custom build DataGridColumn event problem

G

Girish

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"));
}
}
}
 
G

Guest

Girish said:
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.

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
 
G

Girish

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


Phillip Williams said:
Girish said:
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.

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
 
G

Guest

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
--
http://www.webswapp.com


Girish said:
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


Phillip Williams said:
Girish said:
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.

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
 
G

girish

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


Phillip Williams said:
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
--
http://www.webswapp.com


Girish said:
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


Phillip Williams said:
:

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.

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
 
G

Guest

girish said:
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/d...us/cpguide/html/cpconbubblingcommandevent.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
 
G

Guest

girish said:
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/d...en-us/cpguide/html/cpconeventsmini-sample.asp

http://msdn.microsoft.com/library/d.../cpguide/html/cpconcompositecontrolsample.asp

Hope this helps.

Phillip
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top