问题
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:
- Page load: display basic data.
- User clicks on a Submit button which creates a
GridView, which has aButtonField. Both theGridViewand theButtonFieldget created dynamically on the backend. - User then clicks on the generated Button and it should fire the
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?
Edit: Here is the ASPX Page:
<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>
回答1:
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.
回答2:
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.
来源:https://stackoverflow.com/questions/11144580/rowcommand-not-firing