Hi everyoneThis is my first post on stackoverflow (which btw is by far my favourite site for finding answers). After finally admitting defeat, I'm hoping someone can help me with this problem...
The question has already been asked several times, but none of the suggested solutions I found has helped. Apologies in advance for a lengthy post, but I want to avoid anyone wasting their time on suggesting things I tried already.
The code below worked until recently, and its structure has not been touched since (although unrelated changes were made to the child page). In any event, it suddenly stopped working. Now even the most simplified button won’t fire.
Setup
VS 2008 C#, IIS 7 (no changes in setup since way before it stopped working)
nested masterpage (main + 1 child)
dynamically loaded ucl with datalist in child page
(i.e. MP => nested MP => child page => ucl => datalist => linkbutton)
linkbutton click event also resides in ucl
Problem
On LB click, the postback occurs ok, but the server-side click event never gets hit.
Code
page:
var ctrlX = base.LoadControl("~/somedir/someucl.ascx");
=> loads fine
ascx file (datalist stripped of all but the button):
<asp:DataList ID="dlX" RepeatLayout="Table" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:LinkButton ID="btnX" OnClick="btnX_Click" CausesValidation="false" runat="server" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate></FooterTemplate>
codebehind:
protected void btnX_Click(object sender, EventArgs e)
{
// do something
}
things tried
cleaning the solution
digging out a working backup and checking for code changes
(found none affecting the structure or user control)
setting LinkButton CausesValidation true/false
stripping datalist and LinkButton down to bare essentials
adding AddressOf="btnX.click" to LinkButton
wrapping UpdatePanel one at a time with varying settings around usercontrol datalist linkbutton
reattaching eventhandler in usercontrol init / load event:
IEnumerable<Control> controls = Utils.FlattenChildren(dlX);
foreach (var button in controls.OfType(LinkButton)())
{
if (button.ID.Contains("btnX"))
button.Click += new EventHandler(btnX_Click);
}
Wherever I add above code, all buttons are found and the event is attached, but click event doesn't fire ((LinkButton) = LinkButton inside <>; couldn't get it to display right, still struggling a bit with the editor)
.
adding PostBackUrl manually in page load event
comparing the client ids between load/postback events
=> they always match
That's it. Right now, I can't think of what else to try or check (maybe something in the breakpoint context menu on postback?).
Because the ucl loads fine, and the postback is working ok, I suspect the problem is somewhere in the ucl, rather than the child page loading it. But maybe not.
If at all possible, I want to avoid workarounds (I need the button command argument, not shown above, and am not keen on solutions such as jquery with hidden field or query string).
Apart from anything, I would really like to understand what causes this.
Obviously, I'm missing something... Thanks to anyone taking their time reading/helping with this!
======== as requested additional codebehind =======
I've simplified the parent page code to a minimum, dropping all method calls, and as per Eoins suggestion moved the ucl load in the page's init event. The ucl code remains as shown above. The DL and LB show up fine, and on click the postback is triggered, ucl page load event is hit, but as before, the server click event is not hit.
protected override void OnInit(EventArgs e)
{
var ctrlX = base.LoadControl("~/someucl.ascx");
if (ctrlX == null)
return;
DataList dlX = (DataList)ctrlX.FindControl("dlX");
if (dlX == null)
return;
DummyCollection x = new DummyCollection();
x.Add(null); // ok since the test LB does not draw on the datasource
dlX.DataSource = x;
dlX.DataBind();
pnlX.Controls.Add(ctrlX);
base.OnInit(e);
}
var ctrlX = base.LoadControl("~/somedir/someucl.ascx");
Where exactly does this code live on your page?
You'll need to make sure you're creating it and adding it to the control collection early enough in the page lifecycle so that on subsequent postbacks its created & wired up in time. I.e. in the oninit event.
protected override OnInit(...)
{
base.OnInit(...);
var ctrlX = base.LoadControl("~/somedir/someucl.ascx");
this.Controls.Add(ctrlX);
}
Related
Here's some background to help better understand the problem:
The company I work for makes x-ray scanners for security purposes. We have a page in our web app for viewing current scan activity. Currently, it's set to refresh every minute. I've been tasked with reworking the page so that it's event driven, refreshing every time a scan is saved. The information is displayed in a GridView, which is inside an update panel. The first column contains a thumbnail image of the scan, and an Ajax HoverMenuExtender for the purpose of enlarging the thumbnail when the cursor hovers over it.
When the page loads, everything works fine. I assume this is because all the extenders are created before the OnPreRender event is handled. Upon my scan event being fired, however, it fails when the GridView.DataBind() method is called. I assume this is because the OnPreRender event already occurred when the page first loaded and, as the exception says, extender controls may not be registered after prerender.
I've done a lot of digging on this exception, but have yet to find a solution that works. I read that moving the ToolkitScriptManager to the master page can fix it, but it's already on the master page. I also tried overloading the OnInit and OnPreRender handlers as follows:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (this.DesignerMode)
{
this.EnsureChildControls();
}
this.Page.RegisterRequiresControlState(this);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
}
I tried putting that on the current activity page, the master page, and the base page, all to no avail.
I've come across slews of answers simply saying to register the controls before the prerender, which of course makes sense, but since new controls are being created dynamically upon event trigger after the initial page load, how can I accomplish that? Unfortunately, I just don't understand this well enough to know what else to try.
I am new in ASP.NET and I have a problem..
In my code, btn.Click event does not work for multi buttons what created in tab button control. Can you guys advice me?
Thanks,
<asp:Button Text="TAB MENU" BorderStyle="None" ID="Tab" CssClass="Initial" runat="server" OnClick="Tab_Click" />
<asp:Panel ID="panel1" runat="server" Direction="LeftToRight" HorizontalAlign="Left"></asp:Panel>
protected void Tab_Click(object sender, EventArgs e) {
foreach (...) {
Button btn = new Button();
btn.Click += Button1_Click;
panel1.Controls.Add(btn);
}
}
protected void Button1_Click(object sender, EventArgs e) {
**some code here! but does not work.**
}
Try this
Button btn = new Button();
btn.Click += new RoutedEventHandler(Button1_Click);
panel1.Controls.Add(btn);
Your problem probably lies along the lines of the fact that the button does not exist when the Button1_Click callback is fired... Asp.net webforms is a somewhat leaky abstraction over HTTP, and therefore it's a bit tough to decipher sometimes, but I expect what is happening is that when the postback from your button click occurs, the button doesn't actually EXIST in the control tree, because that button only gets added to the control tree when a tab control is clicked. So because the button does not exist on the postback, webforms doesn't know what to do with the event, so it ignores it...
If your buttons must be created dynamically, consider making them do some javascript to edit some hidden field or something, the value of which you can inspect in the Page_Load method, and then do whatever you want to do functionality-wise with that value.
If they are NOT dynamic, and instead will be the same for each page load (but different for each tab - ie, when the page is loaded, you're drawing some info from a db to decide what buttons to display, but that will not change from postback to postback of the same page), then consider creating the buttons in the Page_Load event instead of inside the event that is raised when the tab is created.
ALTERNATIVELY, since in your comment you suggest that the buttons will be used to open a new window, why not just make the buttons do that client side, ie with javascript window.open commands. Then you don't even need to postback to the server at all...
So I'm currently trying to add to each day of a .net calendar control one dynamic linkbutton (on the dayRender event). The problem I have is that the linkbutton href does not appear. It's not a problem of the linkbutton event not firing, the href= doesn't even appear, so it doesn't fire any postback. This means that the button looks like this in the html part:
<a class="delete79" ID="Delete_2014-09-01"> Delete </a>
My code looks like this:
protected void MyCalendar79_DayRender(object sender, DayRenderEventArgs e)
{
List<MenuDia> dayList = new List<MenuDia>();
foreach (var itemMenu in ListMenuDays)
{
if (itemMenu.Dia.CompareTo(e.Day.Date) == 0)
{
dayList.Add(itemMenu);
}
}
LinkButton deleteButton = new LinkButton();
deleteButton.CssClass = "delete79";
deleteButton.Text = "Delete";
deleteButton.ID = "Delete79_" + dayList[0].Dia.ToString("yyyy-MM-dd");
deleteButton.Click += delegate(object o, System.EventArgs a)
{
//simple stuff here, tried putting simple generic response.redirect
//and stuff like that but it wasn't the problem
};
}
I don't wanna sound rude but don't tell me that it's because I'm using a delegate instead of an eventhandler. First of all I tried changing that already (same thing happened) and second I usually do it like this when it's super simple so I don't have to create a separate method.
Also, I've tried changing the ID to something more predictable (Delete_+a simple index), that's not the problem unfortunately =(.
Any other ideas? Maybe it's because I'm doing it on dayrender and you can't do it there? How can I achieve the same thing then?
So yeah I found the problem. MSDN page says:
Because the DayRender event is raised while the Calendar control is
being rendered, you cannot add a control that can also raise an event,
such as LinkButton. You can only add static controls, such as
System.Web.UI.LiteralControl, Label, Image, and HyperLink.
That's the problem. I will do a hack manually that generates the same postback of a hidden linkbutton. Thanks everyone!
There is an exisiting page I am working on at where I work, and there is a checkbox in the ascx , and it has a CheckedChange event for it in its .cs The problem I am having with that page is that when i run the website and check the box, it never fires the event, instead it goes through the On_Load event and it never pass throgh the event... I am not sure why it is not firing the event...
<asp:CheckBox runat="server" ID="OptionSelected"
OnCheckedChanged="OptionSelected_CheckedChanged"
AutoPostBack="true" />
<asp:Label runat="server" ID="OptionHeader"></asp:Label>
protected void OptionSelected_CheckedChanged(object sender, EventArgs e)
{
//some code here
}
PS: This is a control ascx sorry, I forgot to mention. Also another symptom is that the page where that control is... it refreshes unexpectedly, clears some data (including the checkbox if it is checked) and cant figure out what it is causing it.
Any ideas of the reason why this might be happening? things i should look for?
public PortalInfoPortal myPortal
{
get
{
return portal.GetPortalInfo();
}
}
protected void Page_Load(object sender, EventArgs e)
{
//added this an nothing
OptionSelected.CheckedChanged += new EventHandler(OptionSelected_CheckedChanged);
if (myPortal != null)
{
lblOptionMsg.Text = "(" + myPortal.MaxOptionSelectedCharacters.ToString() + " char max)";
txtMessage.MaxLength = myPortal.MaxOptionSelectedCharacters;
var maxLength = myPortal.MaxOptionSelectedCharacters;
maxCheck.ValidationExpression = #"^[\s\S]{0," + maxLength.ToString() + "}$";
}
//There is no binding of any type here
}
you need to have viewstate turned on to have changed events fire. viewstate is how the server knows what the state of the control was when the page was originally served and before it was posted back. without this information, it doesn't know whether the value has changed. check to see if you have viewstate enabled.
Are you perhaps creating the usercontrol (using Page.LoadControl()) and adding it to the control tree dynamically and then forgetting that those steps need to be performed on every postback? Otherwise, the usercontrol no longer exists on postback and none of its events will be fired.
I'm trying to change the visibility of a pair of server controls (specifically a LinkButton and Label) that are nested inside the ItemTemplate part of a repeater during the onclick event of the same LinkButton. I've actually already found a solution, but I don't understand why it works and not the way I was trying before. What I was trying originally is as follows:
Nested inside the ItemTemplate of a repeater
<asp:LinkButton ID="lnAdd" CommandArgument='<%#Eval("index") %>' runat="server" Text="Add" OnClick="lnAdd_Click"> </asp:LinkButton>
<asp:Label Visible="false" runat="server" ID="videoAdded" Text="Video Added"></asp:Label>
Then inside of that lnAdd_Click function I have:
Repeater1.FindControl("lnAdd").Visible = false;
Repeater1.FindControl("videoAdded").Visible = true;
where Repeater1 is the id of the repeater these controls are in. This appears to do nothing (though it compiles). I assume this is because for some unknown reason those controls are not found.
What does work is the last answer of the following question: Server controls in an asp.net repeater
The solution appears to be doing something very similar what I've tried to do. Its even using FindControl on a repeater. The only difference (that I can see) is that it obtains the repeater via the sender object. Hmmm, actually, now that I think about it the id of the elements are changed by .Net to some nonesense like ctl00_ContentPlaceHolder1_Repeater1_ctl02_lnAdd when this is actually run, so perhaps that's why its not finding it. But at the same time, in the working solution I just give the normal ID like "lnAdd". Is .Net automatically translating it? Why would it do it for this solution and not for how I was trying to do it originally?
Anyway, I feel like there's something fundamental here that I'm not quite grasping and would appreciate some enlightenment :D
The problem with using Repeater1.FindControl(..)... is that you can't tell which particular Label or LinkButton is being targeted. It's a repeater, so each such item gets assigned a unique identifier as part of the RepeaterItemCollection. In the markup you name it "lnAdd" but that's not what it will be once generated etc.
For reference, here's the code you said worked from the other post:
protected void btnUpdate_OnClick(object sender, EventArgs e)
{
Button b = sender as Button;
if (b != null)
{
RepeaterItem ri = b.Parent as RepeaterItem;
if (ri != null)
{
string name = null;
//Fetch data
TextBox txtName = ri.FindControl("txtName") as TextBox;
I'll explain the reason the above works. First, the button that was clicked is cast from the sender object. We know it's a button since it's the Update button's click handler. Next, we also know that the button appears in a repeater, so it's parent is a RepeaterItem. That's how the ri variable is initialized and cast. With ri available to us, using FindControl on it will now find the given control in that particular RepeaterItem.
You need to call the FindControl on the RepeaterItem that contains the button that was clicked, you do this in the OnItemCommand handler of the repeater, so you get the instance of the RepeaterItem that caused the command.
You have to add a OnItemCommand="ProcessCommands" in the repeater header and then add a ProcessCommand member:
protected void ProcessCommands(object source, RepeaterCommandEventArgs e)
{
LinkButton button = (LinkButton)e.Item.FindControl("lbAdd");
button.Visible = false;
...
}
Hope this helps