I'm building a dynamic button view, which adds buttons programmatically depending on the amount of items in the database. Like a simple workflow engine. On the first page call the event handler works like expected. The new page with the new item is builded and returned to the client. On the second postback the event handler is NOT called and the view keeps the same items. By reclicking the same button (third postback), the breakpoint in the event handler is hitted.
My issue is why is the event handler not called even if i'm rebuilding the page (override OnInit()) on each post back?
For information: The methods LoadViewWithAlphabeticalDatasource() and LoadViewWithWorkflowItem() does quite the same, so i deleted one in section below. The events are added in same way.
Code:
<pre>
namespace EPS.Web.View.Article
{
public class DynamicGridView : BasePage, IDynamicGridView
{
protected override void OnInit(EventArgs e)
{
Presenter = new DynamicGridPresenter(this);
if (IsPostBack)
{
if (Presenter.Step smallerthan 2)
{
LoadViewWithAlphabeticalDatasource();
}
else
{
LoadViewWithWorkflowItem();
}
}
}
[PageMethod]
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
SetSubmenuVisible = false;
Presenter.InitView();
PrepareView();
}
AddEvents();
AddLabels();
PageMethodsEngine.InvokeMethod(this);
}
private void Back_Clicked(object sender, EventArgs e)
{
Presenter.StepEngine(DynamicGridPresenter.BACK, string.Empty, string.Empty);
PrepareView();
}
private void Cancel_Clicked(object sender, EventArgs e)
{
Presenter.StepEngine(DynamicGridPresenter.CANCEL, string.Empty, string.Empty);
PrepareView();
}
private void ForwardString(object sender, EventArgs e)
{
Presenter.StepEngine(DynamicGridPresenter.FORWARD, ((LinkButton)sender).CommandArgument, string.Empty);
PrepareView();
}
private void ForwardWorkflowItem(object sender, EventArgs e)
{
Presenter.StepEngine(DynamicGridPresenter.FORWARD, string.Empty, ((LinkButton)sender).CommandArgument);
PrepareView();
}
protected void PrepareView()
{
phDynamicGridView.Controls.Clear();
if (Presenter.Step smallerthan 2)
{
LoadViewWithAlphabeticalDatasource();
}
else
{
LoadViewWithWorkflowItem();
}
}
private void LoadViewWithWorkflowItem()
{
var table = new HtmlTable();
table.Attributes.Add("class", "tableDynamicGrid");
int max = GetRowLength(WODatasource.Count);
int temp = 1;
int actualPosition = 0;
int itr = 1;
var tr = new HtmlTableRow();
if (WODatasource.Count == 0)
{
phDynamicGridView.Controls.Add(new HtmlTable());
return;
}
foreach (WorkflowItem s in WODatasource)
{
if (actualPosition biggerOrEqual MaxLength && temp smallerOrEqual max)
{
table.Rows.Add(tr);
actualPosition = 0;
temp++;
tr = new HtmlTableRow();
}
actualPosition++;
var cell = new HtmlTableCell();
// cell.Attributes.Add("class", "cellDynamicGrid");
var btn = new LinkButton
{
CommandArgument = s.Oid.ToString(),
Text = s.SelectionItem.Name /*, CssClass = "linkButtonDynamicGrid"*/
};
btn.Click += ForwardWorkflowItem;
cell.Controls.Add(btn);
tr.Cells.Add(cell);
if (itr == WODatasource.Count && temp smallerOrEqual max)
{
while (itr biggerOrEqual WODatasource.Count && itr smallerThan max*MaxLength)
{
tr.Cells.Add(new HtmlTableCell());
itr++;
}
table.Rows.Add(tr);
phDynamicGridView.Controls.Add(table);
return;
}
itr++;
}
}
}
</pre>
OnInit happens before LoadPostData is called, and this is the reason it appears to work on the second click. What's actually happening is that you are handling an event from a previous postback.
This is a simplified version of events from Asp.net 1.1; 2.0 has some extra events inserted inbetween, like OnPreInit. The order remains though.
You must use an event from Load or later. Some people choose PreRender, but convention for DataBinding is in Load.
UPDATE
I see you are dynamically adding controls to the controls tree. This is fraught with pitfalls (but is perfectly workable.)
a) ensure you add the dynamic controls EVERY time the page loads, not just on postback. Postback/viewstate persists STATE (i.e. data), not objects. You should add them in OnInit (OnLoad works too, but it is more troublesome to maintain). You are currently only adding on postback, this is why the 2nd postback works (and not the first)
b) only initialize the dynamic controls ONCE, like you would any other control - on [!IsPostBack], in Load.
-Oisin
Thank everbody for helping me out. I found the solution:
I didn't know that the dynamically created button needs a ID value. I suggested that Asp know wich button is created. Unfortunately i was wrong. It seems that .NET compares the ID on the buttons and not the position in ControlTree.
I added
new Button{ID = itr.ToString()}
Now when server rebuilds the site, eventhandler are hitted.
regards x.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With