Here's the thing
I added a button to a webpart which saves some fields to MS-Excel.
var btn = new Button { Text = title, CssClass = css };
btn.Click += (sender,args)=>action();
Container.Controls.Add(btn);
This code is located inside OnInit() method in the WebPart. actionis the Action which does stuff, in this case:
Something.FillExcel(MyData);
Something.SaveExcel();
So what happens is, I click the button, it acts like doing the usual partial postback, and does absolutely nothing. I thought it could be something in the Fill/Save code, then I tried forcing an error just to see if it gets there. It seems the click event never fires, or, if it does, it doesn't run my code (?).
Here's the html, just in case:
<input type="submit" name="ctl00$m$g_b4af4370_c016_4712_9d60_fc8ca077a068$ctl359" value="Enviar Formulário" onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$m$g_b4af4370_c016_4712_9d60_fc8ca077a068$ctl359", "", true, "", "", false, false))" class="button" />
What could be happening?
Thanks in advance!
EDIT: After Cos Callis answered, I put my code inside OnLoad() instead of OnInit(). Here's new code:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var btn = new Button { Text = title, CssClass = css };
btn.Click += new EventHandler((sender,args)=>{
if (myform.Page.IsPostBack)
{
excel.FillExcel(); excel.SaveFile();
}
});
container.Controls.Add(btn);
}
I'm now getting a javascript error: SCRIPT5022: Sys.WebForms.PageRequestManagerServerErrorException: The given key was not present in the dictionary.
Because you are attempting to act on the INIT rather than the load, the data has not yet been attached at the server.
You should find this review of the life cycle of a web request in ASP.NET useful:
http://msdn.microsoft.com/en-us/library/ms178472.aspx.
Here is the relevant extract:
Initialization
During page initialization, controls
on the page are available and each
control's UniqueID property is set. A
master page and themes are also
applied to the page if applicable. If
the current request is a postback, the
postback data has not yet been loaded
and control property values have not
been restored to the values from view
state.
Load
During load, if the current request is
a postback, control properties are
loaded with information recovered from
view state and control state.
During initialization the control "exists" but has not yet been loaded with data from the postback. If you you move your code to "OnLoad" you should achieve the disired results. (Don't forget to wrap that in "if(IsPostback)")
Cheers,
CEC
//added resource: After posting my answer I thought you might find this article useful as well:
http://encosia.com/2007/10/24/are-you-making-these-3-common-aspnet-ajax-mistakes/
Sorry guys found out it was an error inside FillExcel(). I thought I would get that asp yellow page but instead it gives me a script error.
Maybe another common mistake for ajax/jquery/sharepoint newbies.
I'm accepting Cos Callis' reply as answer because he did answer everything I asked.
Related
I'm using the GreyBox js library to display a popup. To give some more general context I've rewritten a solution that was in VB.NET to C#. The code is essentially identical in both, just with the differing syntax used in both. However, the following works in the VB.NET solution but not the C# version:
VB
script = String.Format("GB_showCenter('My Caption', '../MyPage.aspx?number={0}&state={1}&ID={2}',300,600 );", num, MyLabel.Text, Label_id.Text)
ScriptManager.RegisterClientScriptBlock(Me.Page, Me.Page.GetType(), Guid.NewGuid().ToString(), script, True)
This works and when a button is clicked it navigates the user to a new page that has the size restricted. However, the following doesn't work.
C#
script = String.Format("GB_showCenter('MyCaption', '../MyPage.aspx?number={0}&state={1}&ID={2}',300,600 );", num, MyLabel.Text, Label_id.Text);
ScriptManager.RegisterClientScriptBlock(this.Page, this.Page.GetType(), Guid.NewGuid().ToString(), script, true);
What should happen is when I click a link button the text in the MyLabel is evaluated and if the text is the correct one then the string 'script' is set appropriately and registered with the scriptmanager. Running through with the VS2010 debugger this is all happening as expected. However, the user isn't navigated to a new page called 'MyPage.aspx'. The url stays the same and the page goes blank.
What's more interesting is that if I click the scroll bar the current page is briefly displayed along with the new popup shown above it on the same page. So my current theory is that it's something to do with how the javascript is called from the c#. Any ideas?
UPDATE
I went through with the vs2010 debugger and decided to see if MyPage.aspx was hit at all. It wasn't, as I expected. However, I then thought that perhaps it wasn't firing it's Page_Load event. So I added in:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Load += Page_Load;
}
I set a breakpoint on the Page_Load event of MyPage.aspx and this was now being hit. All the logic was being run through correctly, but I was still getting the same issue (blank page etc, url not changing to MyPage.aspx etc).
I found the answer, though it's not really related to GreyBox specifically. I'd incorrectly made something a script when it should have been a link and added incorrect attributes. The type was text/javascript when it should've been text/css. This seemed to make the difference. To give more context I had the following:
HtmlGenericControl Link5 = new HtmlGenericControl();
Link5.TagName = "script";
Link5.Attributes.Add("href", ResolveClientUrl("~/MyApp/Greybox/gb_styles.css"));
Link5.Attributes.Add("rel", "stylesheet");
Link5.Attributes.Add("type", "text/javascript");
Page.Header.Controls.Add(Link5);
The 'TagName' should've been 'link' and the Link5.Attributes.Add("type", "text/javascript") should've been 'text/css'.
I'm fairly sure I know why this occurs, essentially that the control is creating dynamically too late in the page lifecycle for the event wireup system to see it, but I'm not realy sure what to do about it:
I've a ListView that is displaying forum posts for my custom forum. Some posts have attachments. The attachemnts are rendered during the ItemDataBound event: the Item's content is searched for an asp PlaceHolder and an ImageButton is dynamically created and added to the placeholder:
ImageButton ib_Delete = new ImageButton();
ib_Delete.ID = "ib_DeleteAttachment_" + myfile.Id.ToString();
ib_Delete.ImageUrl = "~/images/icons/delete.png";
ib_Delete.Width = 16;
ib_Delete.Height = 16;
ib_Delete.CssClass = "attachmentDeleteButton";
ib_Delete.OnClientClick = "return ConfirmDeleteAttachment();";
ib_Delete.CommandArgument = mf.Id.ToString() + '#' + m.Id;
ib_Delete.Click += new ImageClickEventHandler(DeleteMessageAttachment_Click);
myPlaceHolder.Controls.Add(ib_Delete);
Now, the DeleteMessageAttachment_Click method in the .cs never fires, and indeed the javascript onclick looks like:
onclick="return ConfirmDeleteAttachment();"
I actually copied the ImageButton creation code off another page in the same project, one that doesnt have the ImageButtons rendered in a databinding related event, and code for those on the client side looks like:
onclick="return
ConfirmDeleteAttachment();WebForm_DoPostBackWithOptions(new
WebForm_PostBackOptions("ctl00$ctl00$cphPage$MC2$ib_DeleteAttachment_12345",
"", true, "", "", false, false))"
..so I feel pretty sure that it's a problem because I'm creating my controls at the wrong point in the page lifecycle but question is how do I do it at the right time? Should I, in my Page_Load, precreate a load of ImageButtons and hold them in a class-wide Dictionary<> so I can pull them out at the right time? Would the event wireup system see them if I did this? Just not sure what people do to make sure stuff gets created at the right time so that it can be used at another time..
Thanks all
I encountered some weird behaviour today and I was hoping someone could shed some light on it for me because I'm perplexed.
I have a couple of methods I use to interact with the ui for the sole purpose of displaying error/success/warning messages to the user.
Here is one of them
public static void Confirm(string text)
{
var page = (Page)HttpContext.Current.Handler;
var uiConfirm = new HtmlGenericControl("div")
{
ID = "uiNotify",
InnerHtml = text
};
uiConfirm.Attributes.Add("class", "ui-confirm");
page.Master.FindControl("form1").Controls.AddAt(2, uiConfirm);
}
This works perfectly fine except for one nuance I encountered this morning and I was hoping someone could shed some light on it for me.
I am working on your run of the mill profile editing page. In this page, I am binding a couple of dropdownlists (country, province/state) on page load. I have a submit at the bottom and a click event that fires to update the information, then call the method above to notify the user that their information was successfully updated. This works the first time you click the submit button; the page posts back, the information gets updated in the database, the dynamically added div gets popped in, confirm message is displayed and all is good. However, if you then click the submit button again, it fails stating SelectedItem on the dropdowns I'm binding in the page load is null (Object reference not set to an instance of an object). The dropdown is actually wiped for some reason on the second postback, but not the first.
In sheer desperation after trying everything else, I decided to take out the call to the confirm method... and strangely enough the error disappears and I can update the information on the page as many times as I like.
If I add a generic control statically to the page I'm working on, and change my method slightly so that instead of adding a generic control to the form dynamically it just finds the generic control on the page, that does no produce the same error.
The problem also goes away if I remove the two dropdowns from the page or just stop interacting with them.
Why on earth would adding a dynamic control to the form wipe my dropdowns on postback?
I think you should consider using the PlaceHolder class in your MasterPage, the AddAt(2, uiConfirm) is going to bite you and probably is:
Markup:
.......
<asp:PlaceHolder id="PlaceHolder1"
runat="server"/>
......
Code-behind:
public static void Confirm(string text)
{
var page = (Page)HttpContext.Current.Handler;
var uiConfirm = new HtmlGenericControl("div")
{
ID = "uiNotify",
InnerHtml = text
};
uiConfirm.Attributes.Add("class", "ui-confirm");
//may need to change depending on where you put your placeholder
Control placeHolder = page.Master.FindControl("PlaceHolder1");
placeHolder.Controls.Clear();
placeHolder.Controls.Add(uiConfirm);
}
Simple question here, but I've got a nagging feeling that there's a more interesting solution than the one I've chosen:
Page Two consists of a dropdown, and the change event is handled to execute some query.
protected void ddlSavedQueries_SelectedIndexChanged(object sender, EventArgs e)
{
/* stuff happens */
}
Page One is a home page, where I'm providing another version of that dropdown. I'd like the change event in this case to redirect control to Page Two, and then execute the event handler.
My cheap solution is just a Redirect with a querystring value that is handled on page load. Am I missing a more interesting approach?
If you don't want to ugly things up with a querystring value, I suppose you could put something in Session and pick it up on Page_Load of the second page (and then clear it out of Session). Not exactly an awesome improvement though.
Does the same page always get displayed when you change that dropdown? If so, consider using client side javascript to redirect to the correct page, then fire any logic on the subsequent page in the page_load event. Example using jQuery:
$(function() {
$("select.classyouneedtodefine").change(function() {
document.location.href = "somepage.aspx?value=" + $(this).val();
});
});
haven't tested the above...just shooting from the hip
Sorry, another super basic ASP.NET question. this so embarrassing.
I am reading the article on How to: Pass values between ASP.NET pages
In the second approach, they suggest hooking up a button and directing the user to another page using POST. I don't know how to do this. How do I HTTP POST?
"When the source page uses the HTTP POST action to navigate to the target page, you can retrieve posted values from the Form collection in the target page."
This is how I am sending the user to the new page:
protected void btnSubmitForPost_Click(object sender, EventArgs e)
{
Response.Redirect("GetViaPost.aspx");
}
EDIT
The final solution:
You can use ASP.NET webforms. Do the following: On the first page, create your controls and a button that sends the user to a new page. Handle the click event from this button. As stated below, use Server.Transfer with endResponse=false, instead of Response.Redirect(). When you use Response.Redirect, your post data is cleared out. I did not need to specify action in the form or anything else.
In ASP.NET when you click a button, you're posting the entire page's fields by default (as it's contained within a gigantic <form /> tag last time I checked. You can access these values after clicking the button like this:
string MyPostedValue = Request.Form["MyFormField"];
*Edit as per your update in your question, change Response.Redirect() to Server.Transfer() like this:
protected void btnSubmitForPost_Click(object sender, EventArgs e)
{
Server.Transfer("GetViaPost.aspx", true);
}
Then in your GetViaPost.aspx's page you can get any form/query string variable you passed from your sending page like this:
string MyPostedValue = Request.Form["MyFormField"];
If I'm reading this right, all of these answers are missing the question...
You're looking at posting from one Asp.Net form to another, and one of the methods is what you want to figure out - doing a normal http post. The book or article probably is already telling you about the Server.Transfer as another option if I'm guessing right.
If I'm getting the question right, then the simplest answer is to not use a standard ASP.Net form (with the runat = server attribute) as the starting point, but to use a simple standard html form to post to an asp.net page
<form action = "targetpage.aspx" method="post">
...some form fields here
<input type = "submit">
</form>
If in the codebehind you wire up to the button click event, then click the button. It's a POSTback that happens.
Any controls that you have runat="server" will be accessible by their id (and any values set on them) in the codebehind.
In terms of posting data to other pages, you have a number of options available to you.
The querystring, sessions, cookies and viewstate.
A basic example (with no error handling) given your updated Response.Redirect might be:
int someId = int.Parse(txtBoxOnThePage.Text);
Response.Redirect(string.Format("GetViaPost.aspx?myId={0}", someId));
Then on the GetViaPost page you could pull that out by:
HttpContext.Current.Request.QueryString["myId"]
http://www.asp.net/learn/ is a surprisingly good source of information and tutorials for this kind of learning.
ASP.NET buttons always perform a POST. You can set which page the button posts to using the PostBackUrl property of the button. If you leave this blank, the button will post back to the same page that is resides on.
Check out this article for more information.