Handling ServerClick event of a dynamic HtmlInputSubmit control - asp.net

I am a beginner in ASP .Net programming.
I am developping a little training web application.
I have developped a web form where the user can add items into a cart.
The user's cart matches a session variable.
I check whether the user's cart is empty or not in the Page_PreRender event handler.
If the cart is not empty then a table is inserted into the form.
Each item in the cart matches a line in the table.
An item line contains an HtmlInputSubmit to remove the item from the cart.
Here is the code I have written to create dynamically the "Remove Item" HtmlInputSubmit :
submitSupprimerArt = new HtmlInputSubmit();
cellTblCaddie.Controls.Add(submitSupprimerArt);
submitSupprimerArt.Value = "Supprimer " + article.Id;
submitSupprimerArt.Attributes.Add("articleId", article.Id);
submitSupprimerArt.ServerClick += new EventHandler(submitSupprimerArt_Click);
When the user click the HtmlInputSubmit then a postback is made but the submitSupprimerArt_Click event handler is not called.
Can someone please give me a reason ?

I did not want to but I have finally looked at the solution of the training application.
I can describe operations needed to solve my problem but I can not explain precisely why the operations must be done.
The trick is to declare a PlaceHolder control in the ASPX page.
The PlaceHolder must be filled with "Remove Item" buttons from the Page_Load event handler as follows :
protected void Page_Load(object sender, EventArgs e)
{
// ...
caddie = (ListeArticles)this.Session["caddie"];
if (caddie != null)
{
foreach (Article article in caddie)
{
btnSupprimerArt = new Button();
this.phBoutonsSupprArt.Controls.Add(btnSupprimerArt);
btnSupprimerArt.ID = "btnSupprimerArt" + article.Id;
btnSupprimerArt.Command += new CommandEventHandler(btnSupprimerArt_Command);
btnSupprimerArt.CommandName = article.Id;
btnSupprimerArt.Text = "Supprimer " + article.Id;
}
}
}
The Controls property of the PlaceHolder is cleared from the Page_PreRender event handler.
Then the "Remove Item" buttons are created from the Page_PreRender event handler.
The "Remove Item" buttons are inserted this time into table cells.
Conclusion (Needs probably revision) :
Registering handlers to dynamic control events seems a little tricky.
Apparently every event handlers must be registered after the Page_Load event.

Related

ASP.NET: Postback processed without events being fired

I have a GridView with dynamically created image buttons that should fire command events when clicked. The event handling basically works, except for the very first time a button is clicked. Then, the postback is processed, but the event is not fired.
I have tried to debug this, and it seems to me, that the code executed before and after the first click is exactly the same as for any other clicks. (With the exception that in the first click, the event handler is not called.)
There is some peculiarity in that: The buttons which fire the event are created dynamically through databinding, i.e. databinding must be carried out twice in the page lifecycle: Once on load, in order to make the buttons exist (otherwise, events could not be handled at all), and once before rendering in order to display the new data after the events have been processed.
I have read these posts but they wouldn't match my situation:
ASP.NET LinkButton OnClick Event Is Not Working On Home Page,
LinkButton not firing on production server,
ASP.NET Click() event doesn't fire on second postback
To the details:
The GridView contains image buttons in each row. The images of the buttons are databound. The rows are generated by GridView.DataBind(). To achieve this, I have used the TemplateField with a custom ItemTemplate implementation. The ItemTemplate's InstantiateIn method creates the ImageButton and assigns it the according event handler. Further, the image's DataBinding event is assigned a handler that retrieves the appropriate image based on the respective row's data.
The GridView is placed on a UserControl. The UserControl defines the event handlers for the GridView's events. The code roughly looks as follows:
private DataTable dataTable = new DataTable();
protected SPGridView grid;
protected override void OnLoad(EventArgs e)
{
DoDataBind(); // Creates the grid. This is essential in order for postback events to work.
}
protected override void Render(HtmlTextWriter writer)
{
DoDataBind();
base.Render(writer); // Renews the grid according to the latest changes
}
void ReadButton_Command(object sender, CommandEventArgs e)
{
ImageButton button = (ImageButton)sender;
GridViewRow viewRow = (GridViewRow)button.NamingContainer;
int rowIndex = viewRow.RowIndex;
// rowIndex is used to identify the row in which the button was clicked,
// since the control.ID is equal for all rows.
// [... some code to process the event ...]
}
private void DoDataBind()
{
// [... Some code to fill the dataTable ...]
grid.AutoGenerateColumns = false;
grid.Columns.Clear();
TemplateField templateField = new TemplateField();
templateField.HeaderText = "";
templateField.ItemTemplate = new MyItemTemplate(new CommandEventHandler(ReadButton_Command));
grid.Columns.Add(templateField);
grid.DataSource = this.dataTable.DefaultView;
grid.DataBind();
}
private class MyItemTemplate : ITemplate
{
private CommandEventHandler commandEventHandler;
public MyItemTemplate(CommandEventHandler commandEventHandler)
{
this.commandEventHandler = commandEventHandler;
}
public void InstantiateIn(Control container)
{
ImageButton imageButton = new ImageButton();
imageButton.ID = "btnRead";
imageButton.Command += commandEventHandler;
imageButton.DataBinding += new EventHandler(imageButton_DataBinding);
container.Controls.Add(imageButton);
}
void imageButton_DataBinding(object sender, EventArgs e)
{
// Code to get image URL
}
}
Just to repeat: At each lifecycle, first the OnLoad is executed, which generates the Grid with the ImageButtons. Then, the events are processed. Since the buttons are there, the events usually work. Afterwards, Render is called, which generates the Grid from scratch based upon the new data. This always works, except for the very first time the user clicks on an image button, although I have asserted that the grid and image buttons are also generated when the page is sent to the user for the first time.
Hope that someone can help me understand this or tell me a better solution for my situation.
A couple problems here. Number one, there is no IsPostBack check, which means you're databinding on every load... this is bound to cause some problems, including events not firing. Second, you are calling DoDataBind() twice on every load because you're calling it in OnLoad and Render. Why?
Bind the data ONCE... and then again in reaction to events (if needed).
Other issue... don't bind events to ImageButton in the template fields. This is generally not going to work. Use the ItemCommand event and CommandName/CommandArgument values.
Finally... one last question for you... have you done a comparison (windiff or other tool) on the HTML rendered by the entire page on the first load, and then subsequent loads? Are they EXACTLY the same? Or is there a slight difference... in a control name or PostBack reference?
Well I think the event dispatching happens after page load. In this case, its going to try to run against the controls created by your first data-binding attempt. This controls will have different IDs than when they are recreated later. I'd guess ASP.NET is trying to map the incoming events to a control, not finding a control, and then thats it.
I recommend taking captures of what is in the actual post.
ASP.NET is pretty crummy when it comes to event binding and dynamically created controls. Have fun.
Since in my opinion this is a partial answer, I re-post it this way:
If I use normal Buttons instead of ImageButtons (in the exact same place, i.e. still using MyItemTemplate but instantiating Button instead of ImageButton in "InstantiateIn", it works fine.
If I assert that DoDataBind() is always executed twice before sending the content to the client, it works fine with ImageButtons.
Still puzzled, but whatever...

Row Editing in the grid doesn't work in first click

I have a user control which contains a grid and three buttons for add,edit and delete.
I have placed this user control on an asp.net page.
I have OnClick events for these buttons.
When i click on add and delete buttons it's working fine but when i click on edit button,the onclick event of edit button is fired but the row in the grid doesn't appear in the edit mode, i have to click two times.
I don't know where is the problem.The onclick event handler for edit button is as follows:
protected void btnEditBankAccount_Click(object sender, EventArgs e)
{
grdBankAccounts.EditIndex = grdBankAccounts.SelectedIndex;
grdBankAccounts.RowSelectingEnabled = false;
}
Anyone please help.
my user control has a method which binds the grid to the data source, it's as follows
public void SetSupplierData(SupplierType Supplier)
{
if (Supplier != null)
{
ViewState["SupplierID"] = Supplier.SupplierId;
grdBankAccounts.DataSource = Supplier.BankAccounts;
grdBankAccounts.DataBind();
Session["BankAccounts"] = Supplier.BankAccounts;
}
}
the SetSupplierData method is called from the page where i have my user control.
In order to get this "in-place editing" in grids to work, I typically have to data-bind twice:
once in the OnInit or OnLoad method so that the button click event handlers have the data available to work on
in the OnPreRender method again to show the new values / new state (editing or not)
Marc

handling events of controls added during runtime

I am adding controls dynamically during runtime using a conrolplace holder. i want to add buttons and handle their event. they will do the same thing but with different parameter. here is a sample of the code:
while (dataReader.Read())
{
Button edit = new Button();
PlaceHolderQuestions.Controls.Add(edit);
}
i need to handle the event of the buttons. Thanks
A couple of things:
Firstly you need to make sure the new Controls are added in the Page.OnInit event, so that they are added before the raised events are processed.
They also need to be added again on a postback!
They also need to have a unique ID set.
Finally you can handle the event just like you would in any C# app:
edit.Click += new EventHander(EditButton_Click);
and later in the code:
protected void EditButton_Click(object sender, EventArgs e)
{
// Do Something
}
You can just create a method, then add:
edit.Click += YourMethodName;
As long as the same button is created on postback before the eventhandler is raised, the event will fire.

Creating ASP.NET Button dynamically using ajax call

I want to create a asp.net button control / link button control when user makes an ajax call to my server page (another asp.net page) and I wnt to do something on the button click event of this button. How to do this ? Do i need to use delegate ?
No, you don't need a delegate for this, it will be created for you. In your AJAX callback you should do something like this:
Button btn = new Button();
btn.Click += MyOnClickMethod; // must use +=, not =
btn.Text = "click me";
myUpdatePanel.Controls.Add(btn); // the AJAX UpdatePanel that you want to add it to
myUpdatePanel.Update(); // refresh the panel
The method MyOnClickMethod must have the same signature as a normal Click handler. Something like this will do:
protected void MyOnClickMethod(object sender, EventArgs e)
{
// do something
}
that's about it. There are many intricacies involved with dynamic controls, but the basis is as laid out above.

How do I get dynamically added ASP.NET buttons to fire events?

This is probably a simple question but I am not an ASP.NET developer and I am quite stuck.
I have a simple search routine that returns between zero and several hundred results. Each of these must be added to the page as a button and I want to set the text of the button and the CommandArgument property so that when the button is clicked I can read the CommandArgument back and react accordingly.
However, when I click the button the event does not run at all. How can I get it to run?
The code for building the button list (simplified for readability) is as follows:
foreach (SearchResult sr in searchResults)
{
Button result = new Button();
result.Text = sr.name;
result.CommandArgument = sr.ID.ToString();
AccountSearchResults.Controls.Add(result);
result.Click += new EventHandler(SearchResultClicked);
AccountSearchResults.Controls.Add(new LiteralControl("<br/>"));
}
At the minute to test, I have popped a label on the form to put the CommandArgument in. This code is never executed though.
void SearchResultClicked(object sender, EventArgs e)
{
Label1.Text = ((Button)sender).CommandArgument;
}
You mentioned in another answer that you are adding these when a button is clicked. Looking at your code, I would suggest that you try setting a unique ID for each button added, then ensure that on loading the page that buttons with the same IDs and CommandArgument values are reloaded. When a dynamically loaded button is clicked, it must still exist on the page after postback for the event to fire.
I think the ID is all you need, plus your requirement for the CommandArgument). You could put the ID information in the ViewState if you can't get it repeat without a long search process.
Where are you adding this buttons?
if you are adding them inside another control then the event might be raising in the parent control. This happens on DataRepeaters and DataGrids for example.
I think you need to use the OnCommand event handler, rather than the OnClick i.e. try changing this:
result.Click += new EventHandler(SearchResultClicked);
to this:
result.Command += new EventHandler(SearchResultClicked);
UPDATE
Try changing the type of second argument to your event hander from EventArgs to CommandEventArgs. You might also have to set the CommandName property on your button i.e.
result.CommandName = "foo";

Resources