C# generated dynamic controls not displaying - c#

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.

Related

ajaxfileupload multiple inputs on page

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!

How to programmatically add stuff to contentPlaceHolder?

I have a master page and all of my pages are inheriting it.
For formatting, I thought to place the content that differs from one page to another in a ContentPlaceHolder.
Now, how can I insert everything into that? Since I am planning to populate the ContentPlaceHolder with stuff from a database I suppose I will have to do it programmatically.
How can I add controls to ContentPlace Holder?
I checked other answers, but I cannot access it by its ID.
Should I use multiple ContentPlaceHolders from the beginning? Let's say I want to put movies. Should there be only one with all the images and descriptions and ratings, ore one ContentPlaceHolder for each thing?
I am opened to other solutions, as I have no experience with ASP.
Old question... but I just ran into this issue and this was the #1 post that kept coming up on Google, so figure I'd add my answer since the others didn't work in my case.
Here is how I did it when a regular <asp:Content wouldn't work (though in normal use, the answer #JayC is how you do it):
MasterPage has this ContentPlaceHolder:
<asp:ContentPlaceHolder ID="ScriptsPlace" runat="server"></asp:ContentPlaceHolder>
Had to dynamically add some JavaScript from a User Control. Trying to use the ContentPlaceHolder directly gives this error:
Parser Error Message: Content controls have to be top-level controls
in a content page or a nested master page that references a master
page.
So I wanted to add the script from the code-behind. Here is the Page Load for the .ascx file:
protected void Page_Load(object sender, EventArgs e)
{
ContentPlaceHolder c = Page.Master.FindControl("ScriptsPlace") as ContentPlaceHolder;
if (c != null)
{
LiteralControl l = new LiteralControl();
l.Text="<script type=\"text/javascript\">$(document).ready(function () {js stuff;});</script>";
c.Controls.Add(l);
}
}
UPDATE: So it turns out I had to use this in more places than I expected, and ended up using a way that was much more flexible / readable. In the user control itself, I just wrapped the javascript and anything else that needed to be moved with a regular div.
<div id="_jsDiv" runat="server">
$(document).ready(function() {
//js stuff
});
Other server controls or HTML junk
</div>
And then the code behind will find that div, and then move it into the ContentPlaceHolder.
protected void Page_Load(object sender, EventArgs e)
{
ContentPlaceHolder c = Page.Master.FindControl("ScriptsPlace") as ContentPlaceHolder;
HtmlGenericCOntrol jsDiv = this.FindControl("_jsDiv") as HtmlGenericControl;
if (c != null && jsDiv != null)
{
c.Controls.Add(jsDiv);
}
}
I actually put this code in a custom user control, and I just have my regular user controls inherit from the custom user control, so once I wrap the javascript/etc with a <div id="_jsDiv" runat="server">, the custom user control takes care of the rest and I don't have to do anything in the code behind of the user control.
What normally happens is
you set up your master pages with the proper html and ContentPlaceHolders
you create pages based off that master page. If you use Visual Studio, and tell it to create a new page based upon a existing Master page, it will add the Content areas for you.
you add things to the Content areas in the newly created page.
If you want to dynamically add controls to the master (or any) page, you could add controls to any existing control. If it shouldn't be wrapped in any way, just add a Placeholder (it is an asp.net control).
I did like this
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<asp:Literal ID="jsstuff" runat="server"></asp:Literal>
</asp:Content>
And this went into code behind:
string stuff = #"<script type=""text/javascript"">
var searchBox = 0;
var currentCountry = '';
</script>";
jsstuff.Text = stuff;
If the namespace for content Page and Master page is not same then the content page control not accessible in Codebehind in content page.
Also, check your designer files. if the control not listed in designer file then delete the file and recreate (project->convert to web application)

Sharepoint Webpart posting data to Application Page via PostBackUrl

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]

Dynamically create controls using stringbuilder

i have been trying to create controls dynamically on my web page using the StringBuilder class..and i dont quite seem to get through...
any help would be appreciated.
i am trying to do this...
StringBuilder sbTest = new StringBuilder(string.Empty);
sbTest.Append("<input type=\"text\" id=\"txt1\" runat=\"server\" />");
Response.Write(sbTest.ToString());
The page for sure displays a TextBox on the browser which is easily accessible through JavaScript...but what i want is the control to be available on the Server Side too...so that when the page is posted back to the server i can easliy obtain the value that has been entered by the user into the textbox.
Can any 1 please help me with this....
thank you so much....
Like Torbjörn Hansson says, if you just add a name attribute (and maybe remove runat="server" from your original snippet) you'll be able to access the submitted value but you'll only have a client-side HTML <input /> element.
If you are wanting to dynamically create server-side controls then you'll have to do something like this:
TextBox textbox = new TextBox {
/* take care to create unique ID's if you're adding more than 1 TextBox */
ID = "foo",
Text = "bar"
};
Controls.Add(textbox);
In an answer almost about the something I answered this
You should do the things properly and not trying to reinvent the wheel.
Creating controls Dynamically you can choose 2 ways, the .NET way, or the Javascript way
Both are seen by any of the other, in other words, creating controls using the .NET way, javascript can see and use it and vice versa.
.NET way
in your HTML file add something like
<body>
<form id="form" runat="server">
<asp:PlaceHolder id="ph" runat="server" />
</form>
</body>
in your script part
TextBox txt = new TextBox();
txt.ID = "myTxt";
ph.Controls.Add(txt);
you can easily get that TextBox in javascript using:
var myTxtValue = $("#myText").value();
Javascript Way
var txt = $("<input />", {
id : "myTxt"
});
txt.AppendTo("body");
in .NET you get the value using
string value = Request["myTxt"];
NOTE All javascript lines uses jQuery for simplify results
Provide a name-attribute and access it with:
Request.Form["txt1"]
You can get the value from
Request["txt1"]

ASP.NET Custom non-self-closing control

When building a custom control, how would you access the content between the opening and closing control tags?
<my:tag runat="server">
<p>...markup</p>...
</my:tag>
I am currently successfully using the Render method to output arbitrary markeup, but cannot seem to find out how to access the contained markup.
Take a look at this.Controls. This article :
http://msdn.microsoft.com/en-us/library/system.web.ui.control.controls(VS.71).aspx states "On an ASP.NET page, when controls are added declaratively between the opening and closing tags of a server control, ASP.NET automatically adds the controls to the containing server control's ControlCollection. "
As far as I understand, if you have
<yourcode:yourcontrol id="asdf" runat="server">
<p id="innerP" runat="server">Text here</p>
</yourcode:yourcontrol>
Then it would be possible to call this.FindControl("innerP").text="Other text here, since the P tag is generated on the server side.
However, if you do not have the runat="server" set on the P element:
<yourcode:yourcontrol id="asdf" runat="server">
<p id="innerP">Text here</p>
</yourcode:yourcontrol>
then you only can only find it through this.controls[0] since all the content will be rendered into a single Literal control.
I think you want to do this:
<my:tag runtat="server">
<p><asp:Label id="markupLabel" runat="server"/></p>
</my:tag>
And from the code-behind
markupLabel.text = "Foo";
If you add an ID to the my:tag tag, you should be able to access the controls inside of it using the .Controls collection of the tag.

Categories

Resources