I have a Webpart that contains a couple of dropdowns on an update panel. There is a submit button that has the PostBackUrl set to a sharepoint Application Page
<asp:DropDownList ID="ClassSelector" runat="server" Enabled="False"
AutoPostBack="True" onselectedindexchanged="ClassSelector_SelectedIndexChanged">
<asp:ListItem Selected="True" Value="-null-">Select Class...</asp:ListItem>
<asp:ListItem Value="1">Class 1</asp:ListItem>
</asp:DropDownList>
<asp:Button ID="btnSubmit" runat="server" Text="Show Page" Enabled="False"
PostBackUrl="~/_layouts/MyWebParts/MyAppPage.aspx" />
This works in redirecting the browser to the Application Page I have created, but I am having trouble accessing the form data.
On the Page_Load function of the Application Page I have the following debugging code.
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = "";
foreach (String s in Page.Request.Form.AllKeys)
{
Label1.Text += s + ": " + Page.Request.Form[s] + "<br />";
}
}
This shows that the data I need has in fact been posted to the page.
ctl00$m$g_24a73cf8_8190_4ddb_b38b_bf523b12dbd3$ctl00$SemesterSelector: 28
ctl00$m$g_24a73cf8_8190_4ddb_b38b_bf523b12dbd3$ctl00$ClassSelector: 11-0021-A
But when I try to access this as:
Page.Request.Form["ClassSelector"]
Nothing is returned. I know I must be missing something simple here, but I am not sure what.
Any help is greatly appreciated.
Ah, the ASP.NET master page prefix problem! One of my favorites.
The master page for your application page puts a prefix in front of your server-side controls so that they will be unique. If you end up access your control via the Form collection, you have to access it using not only the control ID, but also the ContentPlaceholder prefix. That's why you see such a large ID dumped out of your debugging logic.
If you want to programmatically get to the ID of the control, you can use FindControl, but you'll have to target the apppropriate content placeholder scope for this. Here's a good tutorial/explanation here (which really emphasizes how complex this can get!).
Of course, the other option you can use is just hard-coding the control id based on what you're seeing from your debugging code...but that won't be reliable if you change content placeholders or more your control to a different container.
I guess the answer depends on how static your controls will be.
Hope this helps. Good luck!!
Well to access it that way you would have to use
Page.Request.Form["ctl00$m$g_24a73cf8_8190_4ddb_b38b_bf523b12dbd3$ctl00$ClassSelector"]
As you can actually see from your code where you set the label text to s plus Request.Form[s]
Related
I'm trying to add a button to the webpage, from the code behind. I have a single empty div on my main page that visible on and off, when needed. However the content I wish to create dynamically as the div content can change dependent on conditions.
I have realised that within my ASP Control I use a / (backslash) which cancels out my HTML. The problem I now have is understanding how I can get around this with code, is there a way to add ASP Controls to the web page? I am open to suggestions outside of the InnerHtml.
I'm creating my Button like so (in my Code Behind):
string buttonout = string.Format("<asp:Button ID=\"helpButton_0\" CommandArgument=\"0\" CssClass=\"HelpButton\" runat=\"server\" Text=\"?\"/>");
innercontent[0] = string.Format("<table><tr><td>Lead Passenger Information</td></tr><tr><td>Here by deafaul we used your detaisl from your profile, if you're not the lead passenger (As in you're booking for someone else) then please change details.</td></tr><tr><td>{0}</td></tr></table>"+ buttonout);
As Said above, The reason this doesn't work is because of InnerHtml hating backslashes, I think.
I do have a solution to this; and that's by adding more divs to the page.
<div id="HelpBoxDiv" runat="server" Visible="false">
<div id="HelpBoxDiv_Top" runat="server" Visible="true">
</div>
<div id="HelpBoxDiv_Bottom" runat="server" Visible="true">
<asp:Button ID="button_HelpBox_false" runat="server" />
</div>
</div>
I would then add my Innerhtml to the _Top Div, instead of the HelpBoxDiv which I am currently doing now. However this solution doesn't teach me anything.
I am hesitant to ask questions here, as I know a lot of question have been asked and I am sure this one has before, but I didn't find a solution. Any help is much appreciated.
Thank you.
I have realised that within my ASP Control I use a / (backslash) which
cancels out my HTML. The problem I now have is understanding how I can
get around this with code, is there a way to add ASP Controls to the
web page? I am open to suggestions outside of the InnerHtml.
You cannot add ASP.Net server control like a literal string.
Instead, you want to add the dynamic server control to the following approach -
ASPX
<asp:PlaceHolder runat="server" ID="PlaceHolder1"></asp:PlaceHolder>
Code Behind
protected void Page_Init(object sender, EventArgs e)
{
var button = new Button
{
ID = "helpButton_0",
CommandArgument = "0",
CssClass = "HelpButton",
Text = "?"
};
button.Command += button_Command;
PlaceHolder1.Controls.Add(button);
}
private void button_Command(object sender, CommandEventArgs e)
{
// Handle dynamic button's command event.
}
Before I begin, I have already seen this question about a very similar topic (as well as this one and this one), none of which answer my question completely. I already understand the concepts presented in these questions/answers, but I have more questions.
A) What happens if you have multiple controls with AutoPostBack="false" and you change a number of them before a postback? Take the following brief example (assume that everything else needed for the page is written correctly and trivially; e.g., Page_Load):
Default.aspx:
<asp:DropDownList ID="ddlFoo" runat="server"
OnSelectedIndexChanged="ddlFoo_Changed" AutoPostBack="false" >
<asp:ListItem Text="a" />
<asp:ListItem Text="b" />
<asp:ListItem Text="c" />
</asp:DropDownList>
<asp:DropDownList ID="ddlBar" runat="server"
OnSelectedIndexChanged="ddlBar_Changed" AutoPostBack="false" >
<asp:ListItem Text="1" />
<asp:ListItem Text="2" />
<asp:ListItem Text="3" />
</asp:DropDownList>
<asp:Button ID="btnQux" runat="sever" Text="Click for PostBack" OnClick="btnQux_Click"
Default.aspx.cs:
protected void ddlFoo_Changed(object sender, EventArgs e)
{
Response.Write("ddlFoo changed to " + ddlFoo.Text + ". ");
}
protected void ddlBar_Changed(object sender, EventArgs e)
{
Response.Write("ddlBar changed to " + ddlBar.Text + ". ");
}
protected void btnQux_Changed(object sender, EventArgs e) { }
Now, say you change ddlFoo to 3 and then ddlBar to b. Then, you click btnQux. You get the following output from Response.Write after clicking:
ddlBar changed to b. ddlFoo changed to 3.
Why does this happen? Do the OnSelectedIndexChanged methods get put into a stack to be called once a postback happens?
B) Why does my webpage load much more quickly when I use this approach and set AutoPostBack="false" for most of my controls? To be specific, I did this for a
CheckBox, a DropDownList, and a TextBox in a GridView, which retrieved ~1200 rows and 27 columns of data and took 10s in VS2008 debug mode versus 310s before. Why would the load/refresh time be so much faster?
EDIT: I released the code earlier this afternoon, and there was no significant difference between the load time of the old (AutoPostBack="true") and new (AutoPostBack="false") versions. I think that perhaps the debugger was doing something extra, which caused the large jump in load time. A better way to rephrase question B) might be this then: What could the debugger have been doing to cause this large jump in load time?
Warning: I'm no ASP.NET expert... If this turns out to be garbage, I'll delete it :)
A) I believe you will see the new values of all the controls, whenever the postback ends up happening, including all the change events, just as you described. The values have changed, after all - the AutoPostBack just affects the timing (and whether the postback occurs at all, of course).
B) There's more Javascript in the HTML delivered with AutoPostBack = True on all the controls, but not enough to make that enormous difference. As noted in your edit, it looks like that was a transient issue anyway - we can't really explain transient issues without more diagnostics.
You can use Fiddler to see what data is moving between client and server.
A. With fiddler you can easily see what data is sent to the server.
For example:
If you have DropDownList ddlFoo, when you click on button, you actually post this information:
POST http:// [server]:[port]/[resource.aspx] HTTP/1.1 Host: [server]:[port]
[Headers...]
_VIEWSTATE[viewstate data stored in html as hidden field value]&_EVENTVALIDATION=[event validaion
data]&ddlFoo=selecteItem&button1=ButtonText
When ASP.NET receives request, it compares ddlFoo's value and invokes it's event.
B. When you set AutoPostBack to true, then this javascript function will be generated:
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
And onchange attribute will be added to ddlFoo. So whenever you change DropdownList item, onchange event will be fired and __doPostBack function will be called, which will auto post back to the server.
Both answers you have gotten so far are correct. The simplified version of it is this:
A) When the form is finally POST'ed to the server, the server compares the form's current state with the ViewState and responds accordingly.
B) Enabling AutoPostBack causes javascript to be generated, and this javascript submits the form (which then triggers the postback).
Why does this happen? Do the OnSelectedIndexChanged methods get put
into a stack to be called once a postback happens?
Events that do not immediately post back (in your case ddlFoo_Changed and ddlBar_Changed) are cached.
Then those cached/pending events are raised along with btnQux's click event, when a page is posted back (by btnQux's click event).
You can read more here - ASP.NET Server Control Event Model
I have Page1.aspx containing
Name: <asp:TextBox ID="txt1" runat="server" />
Page2.aspx tries to access its contents by
TextBox txt2 = (TextBox)PreviousPage.FindControl("txt1");
However I end up getting an Object reference not set to instance of an object exception
I've used PreviousPage before and have had success with this snippet of code I found elsewhere online (Can't remember where I found it!)
So..
Option 1:
On your first page you have your button that takes you to the second page, you need to set the PostBackUrl property to the new page url:
<asp:Button ID="button1" Runat="server" Text="submit" PostBackUrl="~/Page2.aspx" />
(This is presuming that your 1st page is a form that redirects to your Page2.aspx)
Then in the new page's code behind you need to write something along the lines of this:
public void page_load()
{
if(!IsPostBack)
{
TextBox tb = (TextBox)PreviousPage.FindControl("txt2");
Response.Write(tb.Text);}
}
You will need to transfer the value of the previous page's txt2.Text to a textbox or label on the new page if you are wanting to do any more postbacks on the second page, otherwise you will lose that value.
Option 2:
You could also use a Session variable surely to store your data?!
Session["text"] = txt2.Text;
Once your'e in the new page, the last page is probably gone, I'd suggest transferring your data over the session.
I'm using ajaxFileUpload as described here: http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/AjaxFileUpload/AjaxFileUpload.aspx
It is working fine except when I have multiple file upload controls on the same page. Specifically, I am trying to upload different files for different questions. When I upload the first on the page, it works fine, but the one lower down on the page will only upload it's file into the answer for the first question.
I'm not sure that makes sense... so it may help you to know that my page is populated with questions dynamically using ascx files. The document ascx file looks like this:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Document.ascx.cs" Inherits="ScholarshipApplication.controls.questions.Document" %>
<ajaxToolkit:AjaxFileUpload OnUploadComplete="UploadComplete" ID="FileUploadControl" MaximumNumberOfFiles="1" runat="server" AllowedFileTypes="png,jpg,jpeg,pdf,tiff,tif,gif" />
<asp:LinkButton ID="downloadButton" runat="server" CausesValidation="false" OnClick="downloadButton_Click" />
And the code behind:
public void UploadComplete(object sender, AjaxFileUploadEventArgs e)
{
entry.data = e.FileName;
entry.setDocumentData(e.GetContents());
this.downloadButton.Text = e.FileName;
}
My initial thoughts are that somehow I need to help the control's generated javascript to know which question it should be triggering when.
I believe this is a bug in control or this was implemented by some non-obvious reason. Actually, this control doesn't support multiple instances on a page. Consider to use AsyncFileUpload control instead or customize a bit sources of the AjaxFileUpload control. If you prefer second option then you need to download sources from here: http://ajaxcontroltoolkit.codeplex.com/SourceControl/BrowseLatest and change AjaxFileUpload.cs file (here is a path: /Server/AjaxControlToolkit/AjaxFileUpload/AjaxFileUpload.cs). What you need to do is to change ContextKey constant to property for combining context key guid with unique id of control:
public class AjaxFileUpload : ScriptControlBase
{
private const string ContextKeySuffix = "{DA8BEDC8-B952-4d5d-8CC2-59FE922E2923}";
private string ContextKey
{
get { return this.UniqueID + "_" + ContextKeySuffix; }
}
Actually, if you'll look on PreRender method of AjaxFileUpload class you'll easy realize reson for such behavior of this control (the first control handle uploads from all sibling controls on a page).
as per my understanding You need a hidden field variable to identify your question id IN UserControl:
<input type="hidden" id="hdnQuestionId" runat="server"/>
while populating/generating question you need to set this variable , and when you upload the doc , fetch this hidden value and use it.
I created a data attribute named "data-upload-type" on ALL AjaxFileUpload controls and set it to the name of the type. Then I set up the client call to grab that value and set a cookie with the same value. The cookie IS received on the server side functions and I branch based on the value I receive.
Here is an example:
function StartUpload(sender, args) {
var t = $(sender._element).attr('data-upload-type');
document.cookie = 'upload-type=' + $(sender._element).attr('data-upload-type') + ';';
}
<asp:AjaxFileUpload ID="afuUploader1" runat="server" OnClientUploadStart="StartUpload" OnUploadComplete="UploadComplete" OnClientUploadComplete="UploadComplete" data-upload-type="UploadType2"></asp:AjaxFileUpload>
Then in your server side upload call simply check Response.Cookies("upload-type").
Works like a charm!
I have the following C# code on one of my pages:
protected override void Render(HtmlTextWriter writer)
{
//an array named fieldNames is delcared here
writer.Write("<form id=\"Form1\" runat=\"server\" action=\"\">");
writer.Write("<asp:checkboxlist id=\"checkBoxes\" runat=\"server\">");
for (int count = 0; count < fieldNames.GetLength(0); count++)
{ //iterates over the array of field names
writer.Write("<asp:listitem text=" + fieldNames[count] + " value=" + fieldNames[count] + "/>");
}
writer.Write("</asp:checkboxlist>");
writer.Write("</form>");
}
The intent is to create a list of checkboxes which have had their attributes set dynamically.
When run this does not throw any errors but no controls appear on the page.
When I view the source of the page I get the following html:
<form id="Form1" runat="server" action="">
<asp:checkboxlist id="checkBoxes" runat="server">
<asp:listitem text='Spares Part No' value='Spares Part No'/>
<asp:listitem text='Description' value='Description'/>
<asp:listitem text='Site' value='Site'/>
<asp:listitem text='Rack/Bin Number' value='Rack/Bin Number'/>
</asp:checkboxlist>
</form>
Out of interest I posted this in another application and it runs fine with all the controls being displayed.
Is this a problem with the order in which events are called? I am at a bit of a loss as to what to try next so any advice would be great.
Thanks,
Oliver
Basically you can't do this.
The Render event comes very late in the page life cycle. You can't just output ASPX markup because the events that parse the markup, instantiate controls etc have already run.
What you should do is add a PlaceHolder control to your page in the markup, and then in an earlier event (e.g. Init or Load) add the controls you want to that placeholder. Again you can't just write out the ASPX markup however, you need to instantiate the controls, along the lines of:
var checkbox = new CheckboxList { Id = "checkBoxes" };
uxPlaceHolder.Controls.Add(checkbox);
checkbox.Items.Add(new ListItem { Text = "...", Value = "..." });
One way you could achieve what you want would be to use a VirtualPathProvider to generate the markup for .aspx requests as they are requested by the framework. Or you could look at what HTML output you actually want to generate (i.e. a list of input elements with some associated javascript) and render these directly. Both of these should probably be classified as nasty hacks however.
You're rendering server-side code - which the browser doesn't understand.
You have to add the CheckBoxList and its ListItems to the form before the page renders.
The server-side control renders the html for the browser - it is created, normally, by Asp.Net parsing the server-side markup.
You are directly writing html content to browser, so you should use only html tags.