Linking events from controls, when the controls have been created

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I've a situation where I'm creating controls programatically. I'm
programatically creating table cells and rows. I've got an array of data,
and I want to format the data on screen in rows of 4. I get my array,
calculate how many complete rows I need. Then for each of the complete rows,
I format a cell for the data in that array element. When I've completed a
row, I add it to my table. If I have a remainder, I do that at the end.

This works very well. However, I want users to be able to select one of the
images I'm showing by clicking on it. Normally, I would do this by
<asp:Image ID="myImage" runat="server" OnClick="myImage_Click"/>
and I would put the code into
protected void myImageClick(object sender, EventArgs e)
{
Code Here
}

However, because I'm creating the ImageButton controls programatically, I
can't quite get an event wired in. I've created event handlers, but I think
that because each ImageButton class in created in FormatCell, then they are
out of scope in a postback. Does anyone have a way for me to reliably wire
an event handler into a programatically created control?




The code is below

protected void Page_Load(object sender, EventArgs e)
{
int typesPerRow = 4;
if (!IsPostBack)
{

PointType[] types = PointSystem.GetPointTypes();
TableRow tr;

//Display the point types, four in a row.
int rows = types.Length / typesPerRow;
int remainder = types.Length % typesPerRow;
for (int i = 0; i < rows; i++)
{
tr = new TableRow();
for (int j = 0; j < typesPerRow; j++)
{
tr.Cells.Add(FormatCell(types[counter]));
}
emailPointTable.Rows.Add(tr);
}

//Do the last (partial) row
if (remainder != 0)
{
tr = new TableRow();
for (int j = 0; j < remainder; j++)
{
tr.Cells.Add(FormatCell(types[counter]));
}
emailPointTable.Rows.Add(tr);
}
}


private TableCell FormatCell(PointType t)
{
ImageButtton pointPic;
TableCell cell;
LinkButton selectme;

cell = new TableCell();
cell.SkinID = "skinCell";

pointPic = new ImageButton();
pointPic.Click += new ImageClickEventHandler(this.pointTypeSelected);
pointPic.SkinID = "skinImage";
pointPic.ImageUrl = t.ImageLarge;
pointPic.Height = 128;
pointPic.Width = 128;

selectme = new LinkButton();
selectme.Text = t.Name;
selectme.CommandName = "SelectPointType";

cell.Controls.Add(pointPic);
cell.Controls.Add(new LiteralControl("<br/>"));
cell.Controls.Add(selectme);

return cell;
}
 
when you create the control just add the handler

myImage.OnClick += new ImageClickEventHandler(myImageClick);

to get the postback event, you need to recreate the controls (with the
same id's) in OnInit and assign the handlers


-- bruce (sqlwork.com)
 
Hi rival
However, because I'm creating the ImageButton controls programatically, I
can't quite get an event wired in. I've created event handlers, but I
think
that because each ImageButton class in created in FormatCell, then they
are
out of scope in a postback. Does anyone have a way for me to reliably
wire
an event handler into a programatically created control?
you have to execute your code on every time, postback or not.
that means, place your code outside of if(!this.IsPostBack), then that
should work fine.
 
Thanks for this - firstly, Bruce - I'd already got the event linked in as you
described. "you need to recreate the controls (with the
same id's) in OnInit and assign the handlers" was the issue. I didn't want
to do a hundred object declarations in case I need the object! I think you
are driving at the same thing Peter has written below.
"you have to execute your code on every time, postback or not"

I've changed my Page_Load to this:
if (!IsPostBack)
{
emailPointTable.Visible = true;
}
else
{
emailPointTable.Visible = false;
}
PointType[] types = PointSystem.GetPointTypes();
TableRow tr;

//Display the point types, three in a row.
int rows = types.Length / typesPerRow;
int remainder = types.Length % typesPerRow;
int counter = 0;
for (int i = 0; i < rows; i++)
{
tr = new TableRow();
for (int j = 0; j < typesPerRow; j++)
{
tr.Cells.Add(FormatCell(types[counter]));
counter++;
}
emailPointTable.Rows.Add(tr);
}

//Do the last (partial) row
if (remainder != 0)
{
tr = new TableRow();
for (int j = 0; j < remainder; j++)
{
tr.Cells.Add(FormatCell(types[counter]));
counter++;
}
emailPointTable.Rows.Add(tr);
}

So if I'm posting back, I just don't render the table. And it works!
Fantastic help from both Bruce and Peter

Thanks again
 
Back
Top