ASP.NET: Enumerating header elements from codebehind - asp.net

On Page_Load() in the codebehind, I'd like to enumerate all the <link> tags. The purpose being I want want to add a <link> to a CSS file if it isn't specified in the Page's markup.
How can I do this?
I'm thinking I should be able to use LINQ on the collection of elements in the header, no?
Here's my pseudocode:
var pageAlreadyContainsCssLink = false;
foreach(var control in this.Header.Controls) {
if (control.TagName == "link" &&
control.Attributes["href"] == "my_css_file.css") {
pageAlreadyContainsCssLink = true;
break;
}
}
if (pageAlreadyContainsCssLink) {
// Don't add <link> element
return;
}
// Add the <link> to the CSS
this.AddCssLink(...);

The solution is to enumerate the Controls collection as HtmlGeneric controls:
foreach(HtmlControl control in this.Header.Controls)
{
if (control is HtmlLink && control.Attributes["href"] == this.CssFileLinkHref)
{
pageAlreadyContainsCssLink = true;
break;
}
}

Yes, your code should work. However, this situation should be managed at the root, by preventing it from happening so you will not need to code something 'just in case' to deal with it.
Your loop checked for the occurance of the css link, and if it exists then exit. What if there are 2 or more occurance? Do you want to remove the duplicate(s)?
I would suggest using one or combination of the followings:
Masterpage (Single place for you to manage css files)
Theme (All css files are linked automatically ONCE per page request)
Code standandisation
Single custom control within the header for all pages (need to make sure item 3 is in place)
1 and 2 is not applicable to ASP.NET 1.x, 3 and 4 applies to all.

Related

Disabling every input on a page programmatically in ASP.NET

I have tried searching around for this, but what I found was mainly for disabling a single input type.
What I want to do is disable every input type on a single page. Everything. Textboxes, checkboxes the whole lot.
I couldnt figure out how to modify the loops I found, which is why I am asking here, beacause it's likely one of you has a piece of code laying around that can do it.
Thank you in advance.
try below if you like to do it in javascript/jquery
$(document).ready(function(){
$('input').attr('disabled','disabled');
});
OR try below if you want in asp.net
ach control has child controls, so you'd need to use recursion to reach them all:
protected void DisableControls(Control parent, bool State) {
foreach(Control c in parent.Controls) {
if (c is DropDownList) {
((DropDownList)(c)).Enabled = State;
}
DisableControls(c, State);
}
}
Then call it like so:
protected void Event_Name(...) {
DisableControls(Page,false); // use whatever top-most control has all the dropdowns or just the page control
} // divs, tables etc. can be called through adding runat="server" property

How to dynamically and incrementally add controls to a container

I thought this was straight forward, but i have a link button, and I do this in the click event:
myContainer.Controls.Add( new FileUpload());
I expect 1 new file control upload to be spawned in the container for each click, however, I always get 1. What do I need to do to have multiple file upload controls?
Since the control was added dynamically, it does not survive the postback. This means that you have to add the file upload (or any other dynamically added control) again in the preinit event to be able to have its values populated and to use it later on in the page life cycle.
Sounds like you are trying to be able to upload multiple files. You may want to add the file uploads with jQuery and use the Request.Files property to get them on the back-end.
I agree with Becuzz's answer. Try this, there are better ways to do it, but this might help as well:
Add this to the "Load" event of your page
if (!IsPostBack) {
Session["UploadControls"] = null;
}
if (Session["UploadControls"] != null) {
if (((List<Control>)Session["UploadControls"]).Count > 0) {
foreach ( ctrl in (List<Control>)Session["UploadControls"]) {
files.Controls.Add(ctrl);
}
}
}
And also add this to the PreInit portion of your page:
string ButtonID = Request.Form("__EVENTTARGET");
if (ButtonID == "Button1") {
FileUpload NewlyAdded = new FileUpload();
List<Control> allControls = new List<Control>();
if (Session["UploadControls"] != null) {
if (((List<Control>)Session["UploadControls"]).Count > 0) {
foreach ( ctrl in (List<Control>)Session["UploadControls"]) {
allControls.Add(ctrl);
//Add existing controls
}
}
}
if (!allControls.Contains(NewlyAdded)) {
allControls.Add(NewlyAdded);
}
Session["UploadControls"] = allControls;
}
And add this to your HTML. This can be anything of course:
<div id="files" runat="server">
</div>
I use the "__EVENTTARGET" value to know what caused the postback, so that you don't get unwanted Upload controls.
Good luck, and hopefully this helps.
Hanlet

Table filled with controls inside an ASP.NET FormView , get controls?

What is the trick to get the controls inside the FormView. I was getting them with FindControl() but, now i cant get access on them. Example: i have some ImageButton on the FooterTemplate, great i can get those smoothly, when it comes to the controls inside the FormView!!! null every control. Do you think i should name them differently in every template?
This gets me thinking about the table causing this noise!
I'm using the DataBound Event and checking for specific Mode! Any ideas? Thank you.
[UPDATED]
This is working
if (this.kataSistimataFormView.CurrentMode == FormViewMode.Edit)
{
ImageButton update = (ImageButton)this.kataSistimataFormView.FindControl("btnUpdate");
update.Visible = true;
But this for some reason no
CheckBox chkBoxPaidoi = kataSistimataFormView.FindControl("chkBoxPaidoi") as CheckBox;
FindControl is not recursive. What I mean is that it will only find controls that are within the child controls of the control you are searching - it will not search any child controls of the child controls
If you have placed the control you previously were looking for within another control then you will have to either search within that new control or, if you still want to use kataSistimataFormView as the parent control, you may have to use a recursive search.
Google for "findcontrol recursive" there are some good examples that you can probably just cut-and-paste.
As it seems this was caused because of the same naming ID's on various templates, Insert,Edit,Item. Even this is supported by the compiler, has problem when you are going for them programmaticaly later.
Thank you all.
Did you ever get this figured out? If you know the ID you can use this recursive function:
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
Found here:
http://www.codinghorror.com/blog/2005/06/recursive-pagefindcontrol.html

change id of a server control in asp.net

Hai guys,
I used find control to find a list item of an unoreder list inside a master page from content page using this,
Control home = this.Page.Master.FindControl("list").FindControl("home");
Now i have to change the id of the control home to "current" because to apply css for it....
Do you know the Type of the control you're finding? Neither Control nor ListItem expose a CssClass property, however, ListItem does expose it's Attributes property.
Update based on comment and other question:
You should be using System.Web.UI.HtmlControls.HtmlGenericControl
So something like this should work for you:
HtmlGenericControl home =
this.Page.Master.FindControl("list").FindControl("home")
as HtmlGenericControl;
string cssToApply = "active_navigation";
if (null != home) {
home.Attributes.Add("class", cssToApply);
}
If you think there might already be an class assigned to it that you need to append to you could do something like:
if (null != home) {
if (home.Attributes.ContainsKey("class")) {
if (!home.Attributes["class"].Contains(cssToApply)){
// If there's already a class attribute, and it doesn't already
// contain the class we want to add:
home.Attributes["class"] += " " + cssToApply;
}
}
else {
// Just add the new class
home.Attributes.Add("class", cssToApply);
}
}
If they aren't ListItems, cast them to the correct type, and modify the attributes collection as before, unless there's a CssClass property for that type.
Yes, to use css id's in asp.net is a big problem. first of all you can change your server control's id to what you want but, this will be regenerated by ASP.NET depending on the position of the control in your page's control tree.
My recommendation is to use cssclass property of the controls, and to replace the css ids to class.

How can I tell whether a JavaScript file has already been included in an ASP.NET page?

I have an ASP.NET user control (.ascx file). In this user control I want to use a .js file.
So I include <script src="file.js" type"text/javascript"></script> on the page.
However, sometimes I use this user control in a webpage where this same script has already been loaded.
How can I add a <script /> declaration that will render on the page only if the page doesn't already contain another <script /> tag for the same script?
As you are using asp.net, it makes sense to do the check server-side as that will be where you choose to add the reference to the javascript file. From your .ascx file you could register with the following:
this.Page.ClientScript.RegisterClientScriptInclude("GlobalUnqiueKey", UrlOfJavascriptFile);
... from your page you just call the ClientScript object directly:
ClientScript.RegisterClientScriptInclude("GlobalUnqiueKey", UrlOfJavascriptFile);
The 'GlobalUniqueKey' can be any string (I use the url of the javascript file for this too)
If you try to register a script with the same key string, it doesn't do anything. So if you call this in your page, your control or anywhere else, you'll end up with only one reference in your page. The benefit of this is that you can have multiple instances of a control on a page and even though they all try to register the same script, it is only ever done a maximum of one time. And none of them need to worry about the script being already registered.
There is a 'IsClientScriptIncludeRegistered(stringkey)' method which you can use to see if a script has already been included under that key but it seems pretty redundant to do that check before registering as multiple attempts to register do not throw exceptions or cause any other errors.
Doing the check client-side means that, assuming the multiple javascript references are cached by the browser (they may not be), you still have multiple tags and the over head of each one causing some javascript to run. If you had 20 instances of your control on a page, you could get serious issues.
You can do one of two things client side...
Check the dom for the script tag corresponding to the javascript file your want to check
Test a variable or function you know has/will be defined within the javascript file for undefined.
Here's a quick JS function which uses JQuery to do what you need:
function requireOnce(url) {
if (!$("script[src='" + url + "']").length) {
$('head').append("<script type='text/javascript' src='" + url + "'></script>");
}
}
use something like the following:
if(typeof myObjectOrFunctionDecalredInThisScript != 'undefined') {
// code goes here
var myObjectOrFunctionDecalredInThisScript = { };
}
This tests if your object or function already exists and thus prevents redeclaration.
var storePath = [];
function include(path){
if(!storePath[path]){
storePath[path]= true;
var e = document.createElement("script");
e.src = path;
e.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(e);
return false;
} }
use this in your main page and call function include with argument javascript file name
As you want to include javascript on one page of your site only.
If you use Asp.net(4.0) then it is very easy.
Just include following code
<script type="text/javascript" scr="filepath and name here"></script>
in ContentPlaceHolder of content page.
#Shimmy I am coming across this after a long while but maybe it might still be useful or at least help other coming from behind. To check if jquery is already loaded do this
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.x.x.min.js"><\/script>')</script>
Don't miss the escape character in the closing script tag in document.write statement.
#mysomic, why did I not think of that. thumbs up
PS: I would have loved to write this right under the line where #Shimmy wrote that jQuery itself is the script he wants to load. But dont know how to write it there. cant see a reply or anything similar link. This may sound dumb but maybe I'm missing something. Pls point it out, anybody?
If you need it from server side, and Page.ClientScript.RegisterClientScriptInclude won't work for you in case script was included by some other way other then Page.ClientScript.RegisterClientScript (for example page.Header.Controls.Add(..), you can use something like this:
static public void AddJsFileToHeadIfNotExists(Page page, string jsRelativePath)
{
foreach (Control ctrl in page.Header.Controls)
{
if (ctrl is HtmlLink htmlLink)
{
if (htmlLink.Href.ToLower().Contains(jsRelativePath.ToLower())) return;
}
if (ctrl is ITextControl textControl
&& (textControl is LiteralControl || textControl is Literal))
{
if (textControl.Text.ToLower().Contains(jsRelativePath.ToLower())) return;
}
if (ctrl is HtmlControl htmlControl)
{
if (htmlControl.Attributes["src"]?.ToUpper()
.Contains(jsRelativePath.ToUpper())) return;
}
}
HtmlGenericControl Include = new HtmlGenericControl("script");
Include.Attributes.Add("type", "text/javascript");
Include.Attributes.Add("src", page.ResolveUrl(jsRelativePath));
page.Header.Controls.Add(Include);
}

Resources