Asp.Net - UserControl - Inherit from MasterPage - c#

Is it possible for an user control (ascx) to doing something like herit from a MasterPage ?
My point is, in one of my user control (only use by one kind of MasterPage), I would like to use an <asp:content> tag, but I can't, I can only in the page that use that user control...
So, I have to repeat some code into each of the page that use that user control...
Update
For example, each time, I need to add something like that :
<asp:Content ID="cntJavascript" ContentPlaceHolderID="cphJavascript" runat="server">
<script type="text/javascript" src="<%= Url.Content("~/Content/js/UcJs.js") %>"></script>
</asp:Content>
That because, I want all my Js files on the same place in my MasterPage and I only want to add Js that is needed

I think the answer you're looking for is to use Page.RegisterClientScriptInclude in each of the controls that require the supporting Javascript code, using the same key value each time.
In this way, the Javascript file will be included only once no matter how many controls require it.
internal static void RegisterJavascriptInclude(Page page, string includeFile)
{
string key = includeFile.ToLowerInvariant();
if (!page.ClientScript.IsClientScriptIncludeRegistered(key))
page.ClientScript.RegisterClientScriptInclude(key, page.ResolveClientUrl(includeFile));
}

I assume your user controls output the javascript url which is different for each user control. There are a couple ways I can think of to do this.
Add a method in your masterpage like:
void AddJavascriptFile(string url) {
this.ContentPlaceHolder1.Controls.Add(
new LiteralControl(
"<script type='text/javascript' src='" + url + "'></script>"));
}
...then in your user control you can add your javascript like so:
((MyMasterPage)((System.Web.UI.Page)this.Parent).Master).AddJavascriptFile(
"http://example.com/javascript.js");
This might point you in the right direction - I'm still not entirely sure what you're trying to do.

Related

C# access element in master page from logic layer

I have a content page connected to a master page. I can access an element on the master page and modify it directly from the content page .cs file by calling a method on the site master. (this is probably the most standard bug people have in this type of area)
My problem is that I wanted to extend this functionality to update the site master page from an AJAX request as well. The ajax file calls a different page which in turns starts an instance of the logic layer which I use for all the calculations and connections. What I am trying to do is access the sitemaster directly from the logic layer (only a .cs file).
My current code is this:
SiteMaster sm = new SiteMaster();
sm.MyMethod("param1", "param2");
This successfully accesses the method called "MyMethod" in the site master but inside this method I have this code:
mySpan.InnerText = "this is a test";
which doesn't work because I get the "Object refernce not set to an instance of an object...." error. This is because mySpan is NULL. If I call it using this.mySpan.InnerText though, if I hover over "this" then I can see the ID "mySpan".
Does anyone know how I can get around this problem? Every search I have made is regarding people who want to access the elements from the content page which already works for me.
I believe you've got a misunderstanding here. If I understand correctly you've got a page with a MasterPage. On that aspx page you're doing an ajax call (perhaps to a WebService) which does something like:
[WebMethod]
public void UpdateText(string message)
{
var master = new SiteMaster();
master.mySpan.Text = message;
}
There are a couple of things wrong here.
When you use this approach is an aspx page you're updating that Page's master. For example:
public void OnSomeRandomButtonClick(object sender, EventArgs e)
{
((SiteMaster)this.Page.Master).mySpan.Text = "Some Text";
}
What you're doing here is updating the span on the master page before it's being sent to your browser. The other subtly is that you're not creating a new SiteMaster, you're using the Page's existing Master and casting it to a SiteMaster.
There are a couple of reasons you can't do this with ajax:
A webservice doesn't have a MasterPage
By the time you send an ajax request your Master page has already been created and sent to the browser.
So your question becomes how do we update a span in the Master without posting back to the server?
Lets look at the html which is actually on your box, it will look something like this:
<html>
<head>
<title>My Awesome Page</title>
</head>
<body>
<h1>This is my Awesome Website</h1>
<span id="mySpan">I'm sure you'll like it</span>
<div>
<p>Page Content</p>
<div>
</body>
</html>
Lets assume that everything here is generated by the master and only the <p>Page Content</p> is your aspx page (There will also be loads of ASP.NET junk added, we'll ignore that for the time being).
What you want to do is update the text in mySpan without posting back to the server. You can do this via the javascript - don't get ajax involved at all!
I'm going to assume you're using jQuery (mostly because I'm more familiar with it that plain old JS). You've got the ID of your span ("mySpan") so the rest is easy:
$('#mySpan').html('This is the updated message');
You can put this in either a click or a page load.
No. You can not simply construct an ASP.NET page and use its state.
ASP.NET pages (and controls and Master pages) are being constructed and initialized from inside the ASP.NET engine based on the Markup provided for them. There is for example no initialization for mySpan inside the codeBehind of your master page, that will be constructed when the code generated based on the Markup is invoked based on a user request.
So you define this in your class:
protected HtmlGenericControl mySpan;
But the ASP.NET engine will compile this markup
<span id="mySpan" style="color:green"></span>
to this code:
this.mySpan = new HtmlGenericControl();
this.mySpan.Style.Add("color", "green);
and that is why you can use this object inside your code.
So if you want to use a property of your Master page from your Business layer, you have so many choices. On of the fastest one to implement is to make your Logic class singleton inside the Session scope, store the value you want to use inside the master page into that singleton object and then read that value from the master Page. This is an example of what you should do, of course it is rough.
class Logic
{
public static Logic Instance
{
get
{
if (HttpContext.Current.Session["LogicInstance"] == null)
HttpContext.Current.Session["LogicInstance"] = new Logic();
return (Logic) HttpContext.Current.Session["LogicInstance"];
}
}
public string TextForSpan {get;}
// The rest of your implementation
}
Instead of the code to assign the inner text, write:
Logic.Instance.TextForSpan = "This is my text";
And inside your master page:
this.mySpan.InnerText = Logic.Instance.TextForSpan;

Asp.Net: User controls, javascripts and javascript libraries

I have a user control which requires Javascript/Jquery per control. It is actually a control to represent data graphically using some javascript library. As a norm all my javascript links are located at the bottom of the page in the Master Page. This implies I cannot write any javascript in the control because it will appear before any of its dependencies. Also, Even if the script is located at the bottom of the page, it only works for the first control. Has anyone encountered similar challenges? I'm looking for a way out. Thanks
You can register client scripts from code-behind.
var clientScriptManager = Page.ClientScript;
if(!clientScriptManager.IsStartupScriptRegistered("a_key")) { //If multiple control instances are present on the page, register scripts only once
RegisterStartupScript(Page.GetType(), "a_key", "<script src=\"/js/a_library.js\"></script>"));
}
RegisterStartupScript will add <script> tag at the very bottom of the page, before </body> closing tag.
I had a similar issue "updating" a legacy site that had tons of inline JS... so I also ran into issues when I moved jQuery and other scripts to the bottom of the page. I solved it by adding a new ContentPlaceHolder to the master page, underneath the other script references:
<asp:ContentPlaceHolder ID="ScriptsPlace" runat="server"></asp:ContentPlaceHolder>
</body>
Then went through the pages and moved all the inline JS into a content block for ScriptsPlace.
<asp:Content ID="Content5" ContentPlaceHolderID="ScriptsPlace" runat="server">
<script>
//some awesome JS
</script>
</asp:Content>
Although this doesn't work for user controls... so I made a somewhat hacky solution that essentially involved putting all of the user controls JS into a div named _jsDiv and then from the code-behind moving that div into the placeholder (I'm not fond of RegisterStartupScript and it's not practical for a lot of code).
Since I did this in multiple controls, I did these steps:
Step 1 - Make a custom user control, ScriptMoverUserControl.cs:
public class ScriptMoverUserControl : System.Web.UI.UserControl
{
protected void Page_PreRender(object sender, EventArgs e)
{
ContentPlaceHolder c = Page.Master.FindControl("ScriptsPlace") as ContentPlaceHolder;
HtmlGenericControl jsDiv = this.FindControl("_jsDiv") as HtmlGenericControl;
if (c != null && jsDiv != null)
{
jsDiv.ID = Guid.NewGuid().ToString(); //change the ID to avoid ID conflicts if more than one control on page is using this.
c.Controls.Add(jsDiv);
}
}
}
Step 2 - Make your user control use this new control class:
It will inherit ScriptMoverUserControl instead of System.Web.UI.UserControl
public partial class SomeGreatControl : ScriptMoverUserControl
Step 3 - Dump your user control scripts in a div named _jsDiv:
<div id="_jsDiv" runat="server">
<script>
//some awesome JS
</script>
</div>
It's been working fine for me, but if anyone knows a better/cleaner way, I'd like to know!

how to write javascript in asp.net in code behind using C#

How can I write JavaScript code in asp.net in code behind using C#?
For example:
I have click button event when I click the button I want to invoke this java script code:
alert("You pressed Me!");
I want to know how to use java script from code behind.
Actually, this is what you need:
string myScriptValue = "function callMe() {alert('You pressed Me!'); }";
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "myScriptName", myScriptValue, true);
Copy all of javascript into string and then register it into your aspx page in code-behind. Then in aspx page, you can call the javascript function whenever you want. You should write this code in Page_Load method in C# page.
Have a look at the ScriptManager class' RegisterClientScriptBlock and RegisterStartupScript methods.
One way to put some javascript onto the page into a specific location do this:
ASP.Net
<script type="text/javascript">
<asp:Literal id="litScript" runat="server" />
</script>
C#
litScript.Text = "alert("Hello!");"
Of course, you can put anything in there, and I'd recommend a javascript library.
Using the Scriptmanager is also an option.
Not an answer, but a suggestion.
Mixing your js within your code-behind can come back to haunt you, I agree with Adrian Magdas.
Anytime you need to make a simple change/update to your javascript you'll have to re-build your project, which means re-deploying instead of simply pushing out a single .js file.
Something like:
btnSomething.ClientClick = "alert('You pressed me!');";
You might also want to read up on the ScriptManager control and outputting blocks of script.
The right answers usually is "You don't". It's better to define your code in a .js file and use jQuery to hook-up the desired events.
$(document).ready(function() {
$('#myBtn').click(function() {
alert('Handler for .click() called.');
});};
If you want to register a script that will be used in connection with an UpdatePanel (AJAX) use ScriptManager class as Sani Huttunen pointed.
Otherwise you should use the class ClientScriptManager (methods Page.ClientScript.RegisterClientScriptBlock or Page.ClientScript.RegisterStartupScript)
As other user pointed, normally registering a script on the code behind can and should be avoided. It's not a very nice practice and you should do it only in cases where you have no other option.
Response.Write("<script language='javascript'>alert('You pressed Me!');</script>");

Detect if a page is within a iframe - serverside

How can I detect server-side (c#, asp.net mvc) if the loaded page is within a iframe? Thanks
This is not possible, however.
<iframe src="mypage?iframe=yes"></iframe>
and then check serverside if the querystring contains iframe=yes
or with the Referer header send by the browser.
Use the following Code inside the form:
<asp:HiddenField ID="hfIsInIframe" runat="server" />
<script type="text/javascript">
var isInIFrame = (self != top);
$('#<%= hfIsInIframe.ClientID %>').val(isInIFrame);
</script>
Then you can check easily if it's an iFrame in the code-behind:
bool bIsInIFrame = (hfIsInIframe.Value == "true");
Tested and worked for me.
Edit: Please note that you require jQuery to run my code above. To run it without jQuery just use some code like the following (untested) code to set the value of the hidden field:
document.getElementById('<%= hfIsInIframe.ClientID %>').value = isInIFrame;
Edit 2: This only works when the page was loaded once. If someone have idea's to improve this, let me know. In my case I luckily only need the value after an postback.
There is no way of checking this that will fit your requirement of "secure" as stated in your comment on #WTP's answer.
I don't think the server-side can do this, so why not put a hidden control in your page that will be in the iframe? When the URL in the iframe loads, you can add some client-side code to set the hidden input to indicate you are in an iframe. The easiest check would be on the client-side in an onload method, like this:
// Set hidden input
someHiddenInput.value = self != top
It's more secure than the querystring, but it still might not be enough security for you.
My 2 cents.
Old question but why not a more simplistic approach like
var isFramed = self !== parent

Element-Enhancing Javascript in ASP.NET Master Pages

I have run in to a bit of a problem and I have done a bit of digging, but struggling to come up with a conclusive answer/fix.
Basically, I have some javascript (created by a 3rd party) that does some whizzbang stuff to page elements to make them look pretty. The code works great on single pages (i.e. no master), however, when I try and apply the effects to a content page within a master, it does not work.
In short I have a master page which contains the main script reference. All pages will use the script, but the parameters passed to it will differ for the content pages.
Master Page Script Reference
<script src="scripts.js" language="javascript" type="text/javascript" />
Single Page
<script>
MakePretty("elementID");
</script>
As you can see, I need the reference in each page (hence it being in the master) but the actual elements I want to "MakePretty" will change dependant on content.
Content Pages
Now, due to the content page not having a <head> element, I have been using the following code to add it to the master pages <head> element:
HtmlGenericControl ctl = new HtmlGenericControl("script");
ctl.Attributes.Add("language", "javascript");
ctl.InnerHtml = #"MakePretty(""elementID"")";
Master.Page.Header.Controls.Add(ctl);
Now, this fails to work. However, if I replace with something simple like alert("HI!"), all works fine. So the code is being added OK, it just doesn't seem to always execute depending on what it is doing..
Now, having done some digging, I have learned that th content page's Load event is raised before the master pages, which may be having an effect, however, I thought the javascript on the page was all loaded/run at once?
Forgive me if this is a stupid question, but I am still relatively new to using javascript, especially in the master pages scenario.
How can I get content pages to call javascript code which is referenced in the Master page?
Thanks for any/all help on this guys, you will really be helping me out with this work problem.
NOTES:
RegisterStartupScript and the like does not seem to work at any level..
The control ID's are being set fine, even in the MasterPage environment and are rendering as expected.
Apologies if any of this is unclear, I am real tired so if need be please comment if a re-word/clarification is required.
Put a ContentPlaceHolder in the head section of the master page, then add a asp:Content control on the content page referring to the placeholder and put your script in that control. You can customize it for each page this way.
Also, the reference by ID may not be working because when you use Master Pages, the control IDs on the page are automatically created based on the container structure. So instead of "elementID" as expected, it may be outputting "ctl00_MainContentPlaceHolder_elementID" View your source or use firebug to inspect your form elements to see what the IDs outputted are.
Isn't it possible to do with clean javascript ?-)
-- just add something similar to this inside the body-tag:
<script type="text/javascript">
window.onload = function(){
MakePretty("elementID");
}
</script>
By the way the script-tag has to have an end-tag:
<script type="text/javascript" src="myScript.js"></script>
Why not use jQuery to find all the controls? Something like this:
$(document).ready(function(){
$("input[type='text'], input[type='radio'], input[type='checkbox'], select, textarea").each(function(){
MakePretty(this);
});
});
This way you'll get all elements on the page, you can wait until the page is ready (so you don't modify the DOM illigally). The jQuery selector can get the elements in a bit more of a specific format if you need (ie, add a root element, like the ID of the body div).
It'd also be best to modify the MakePretty method so it takes the element not the ID as the parameter to reduce processing overhead.
Once you use Master Pages, the ids of controls on the client side aren't what you think they are. You should use Control.ClientID when you generate the script.
When using master pages, you need to be careful with the html attribute ID, since .NET will modify this value as it needs to keep ids unique.
I would assume your javascript is applying css styles via ID, and when you are using master pages the ID is different than what is in your aspx. If you verify your javascript is always being added, your answer needs to take into account the following:
ALWAYS set your master page id in page load (this.ID = "myPrefix";)
Any HTML element in your master page will be prefixed by the master page id (i.e.: on the rendered page will be "myPrefix_myDiv")
Any HTML element in your content place holder id will be prefixed with an additional prefix (i.e. myPrefix_ContentPlaceHolderId1_myDiv)
Please let me know if I can clarify anything. Hope this helps!

Categories