Reputation: 191
I am trying to programmatically add a button in ASP.NET
with C#
as the backend. I am able to display the button, but the RowCommand isn't getting fired when the user clicks the button.
I believe the problem is that I am creating the buttons after the user clicks on a "Submit" button. If I make the button in the page_load then the RowCommand works.
This is how the website should flow:
GridView
, which has a ButtonField
. Both the GridView
and the ButtonField
get created dynamically on the backend.RowCommand
Here is the code:
Page_load
protected void Page_Load(object sender, EventArgs e)
{
//Nothing because we only want to create the button after the user
//clicks on submit
}
randomGridView
Generates the Gridviews and buttons
public void randomGridView(Table t, int x)
{
GridView gv1 = new GridView();
GridView gv2 = new GridView();
GridView gv3 = new GridView();
GridView gv4 = new GridView();
TableRow r = new TableRow();
for (int i = 0; i < x; i++)
{
TableCell c = new TableCell();
c.BorderStyle = BorderStyle.Solid;
if (i == 0)
{
c.Controls.Add(gv1);
}
if (i == 1)
{
c.Controls.Add(gv2);
}
if (i == 2)
{
c.Controls.Add(gv3);
}
if (i == 3)
{
c.Controls.Add(gv4);
}
r.Cells.Add(c);
}
t.Rows.Add(r);
//Where the xml gets bonded to the data grid
XmlDataSource xds = new XmlDataSource();
xds.Data = xml;
xds.DataBind();
xds.EnableCaching = false;
gv1.DataSource = xds;
ButtonField temp = new ButtonField();
temp.ButtonType = ButtonType.Image;
temp.ImageUrl = "~/checkdailyinventory.bmp";
temp.CommandName = "buttonClicked";
temp.HeaderText = " ";
gv1.Columns.Add(temp);
gv1.RowCommand += new GridViewCommandEventHandler(CustomersGridView_RowCommand);
gv1.RowDataBound += new GridViewRowEventHandler(inventoryGridView_RowDataBound);
gv1.DataBind();
xds.Data = xml;
xds.DataBind();
xds.EnableCaching = false;
gv2.DataSource = xds;
gv2.DataBind();
xds.Data = xml;
xds.DataBind();
xds.EnableCaching = false;
gv3.DataSource = xds;
gv3.DataBind();
xds.Data = xml;
xds.DataBind();
xds.EnableCaching = false;
gv4.DataSource = xds;
gv4.DataBind();
}
inventoryGridView_RowDataBound
Where I tried manaully adding a button to the first cell
public void inventoryGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
Button temp = new Button();
temp.CommandName = "buttonClicked";
temp.Text = "temp button!";
e.Row.Cells[0].Controls.Add(temp);
}
CustomersGridView_RowCommand
This is what needs to get fired
public void CustomersGridView_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "buttonClicked")
{
int index = Convert.ToInt32(e.CommandArgument);
Label1.Text = index.ToString();
}
}
Button1_Click
What actually creates the gridviews and the buttons
public void Button1_Click(object sender, EventArgs e)
{
randomGridView(Table1, 1);
randomGridView(Table2, 4);
}
So how do I get the button to fire CustomersGridView_RowCommand
? Or is it impossible to link a dynamically generated button?
<table>
<tr>
<td>
<div id="div1" style="width: 257px; height: 500px; overflow-x: scroll; overflow-y: hidden;">
<asp:Table ID="Table1" runat="server">
</asp:Table>
</div>
</td>
<td>
<div id="div2" style="width: 500px; height: 500px; overflow: scroll;">
<asp:Table ID="Table2" runat="server">
</asp:Table>
</div>
</td>
</tr>
</table>
Upvotes: 1
Views: 3446
Reputation: 191
I was finally able to get the RowCommand to fire after dynamically creating it. Here is my solution although I cannot say this is the best way of doing things:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (IsPostBack){
if (Request.Form[Button1.UniqueID] != null)
{
//Get the data from the server
randomGridView(Table1, 1);
randomGridView(Table2, 4);
}
//Just display the form here
}
}
Now instead of waiting till I get to the button_click event I check in OnInit if the button was clicked. If it was then I know the user wants me to load the data and display it. Currently in the code above I just make and display data in the same function (Which is a bad design, but I was just simply prototyping).
Then whenever the user clicks on anything that will cause a postback it will then add the table to the controls. Then the controls can fire (I have no idea why or how, but it works..)
Just to show that we don't even need a button function:
public void Button1_Click(object sender, EventArgs e)
{
//randomGridView(Table1, 1);
//randomGridView(Table2, 4);
//Session.Add("doIt",true);
}
Again this probably isn't the best way of doing things, but it works. If someone has a better solution please let me know.
Upvotes: 1
Reputation: 4320
It's not impossible. You need to understand that the control tree (which you supplement with your randomGridView method) is rebuilt automatically when the page is re-loaded from view state, but the event handlers for those dynamically added controls are NOT rebuilt automatically.
In particular, this line which attaches the event handler:
gv1.RowCommand += new GridViewCommandEventHandler(CustomersGridView_RowCommand);
is NOT getting re-executed when you page reloads from view state, which it must do when you click on one of the buttons in the grid and the browser posts the page back to the server.
Your solution will be to check the page for a postback condition in the Load event phase. If Page.IsPostBack is true, scan your control tree for these dynamically generated grids, and set event handlers (like the code above) for the RowCommand event.
Upvotes: 3