I have a Class Library project named "AddJsFunction" which contains a class where I am including all related JS, CSS and Image files. Below is the IncludeJsFile method inside the above mentioned class where I am adding all the Javascript files which works as expected.
public void IncludeJsFile(Page pg)
{
pg.ClientScript.RegisterClientScriptInclude(this.GetType(), "Test2", pg.ClientScript.GetWebResourceUrl(this.GetType(), "AddJsFunction.queue.js"));
string csslink2 = "<script type='text/javascript' language='javascript' src='" + pg.ClientScript.GetWebResourceUrl(this.GetType(), "AddJsFunction.queue.js") + "' />";
LiteralControl include2 = new LiteralControl(csslink2);
pg.Header.Controls.Add(include2);
}
Same way I want to embed the CSS files which i tried to include like shown above but that is not working and I need some help to do the same.
Thanks,
VY.
From Is there a ClientScriptManager.RegisterClientScriptInclude equivalent for CSS:
HtmlLink link = new HtmlLink();
link.Href = "Cases/EditStyles.css";
link.Attributes.Add("type", "text/css");
link.Attributes.Add("rel", "stylesheet");
//check if it exsists on the page header control first
foreach (Control control in pg.Header.Controls)
{
if ((control is HtmlLink) &&
(control as HtmlLink).Href == href)
{
return true;
}
}
pg.Header.Controls.Add(link);
Related
I am just learning how to use classes in my projects. I have been working on a DataAccessClass.cs and am doing well (I think).
Taking a break from data access, I decided to try to make a void into a class. This void sends a message to the client as a javascript alert. It works well, but has to be included on each page. When I tried to make it a class, I was informed that my class does not contain a definition for ClientScript. I included all the "using" directives from the original page to no avail... Any hints or suggestions would be greatly appreciated.
The original code:
//------------------------------------------------------------------------------
//Name: SendErrorMessageToClient
//Abstract: show alert on client side
//------------------------------------------------------------------------------
protected void SendErrorMessageToClient(string strErrorType, string strErrorMessage)
{
string strMessageToClient = "";
//Allow single quotes on client-side in JavaScript
strErrorMessage = strErrorMessage.Replace("'", "\\'");
strMessageToClient = "<script type=\"text/javascript\" language=\"javascript\">alert( '" + strErrorType + "\\n\\n" + strErrorMessage + "' );</script>";
this.ClientScript.RegisterStartupScript(this.GetType(), "ErrorMessage", strMessageToClient);
}
Messages are sent into this void like this:
if (DataAccessClass.OpenSqlConnection(ref Conn, strConn, out strErrorMessage) == false)
{
string strErrorType = "Database Connection Error:";
SendErrorMessageToClient(strErrorType, strErrorMessage);
}
Or this:
catch (Exception excError)
{
string strErrorType = "Unhandled Exception:";
string strErrorMessage = excError.Message;
SendErrorMessageToClient(strErrorType, strErrorMessage);
}
You are receiving the error as 'Clientscript' is a property derived from a System.Web.UI.Page and by moving into a separate class file, you no longer have access to this property.
You could solve this by passing in the page as well, and amending the code to
protected void SendErrorMessageToClient(string strErrorType, string strErrorMessage, Page page)
{
string strMessageToClient = "";
//Allow single quotes on client-side in JavaScript
strErrorMessage = strErrorMessage.Replace("'", "\\'");
strMessageToClient = "<script type=\"text/javascript\" language=\"javascript\">alert( '" + strErrorType + "\\n\\n" + strErrorMessage + "' );</script>";
page.ClientScript.RegisterStartupScript(this.GetType(), "ErrorMessage", strMessageToClient);
}
ClientScript Property is part of the Page class that every ASPX page inherit from. Therefore you can not just use it from inside your class unless it (i.e. your class) has Page as its base class.
this. is for fields in your method in classes.
Why do you want to make this a class? It shouldn't be a class, it doesn't have any properties or fields, unless you can think of one. You do understand if you make it a class you would still have to intialize it on every page.
You could make it a static string method you would still have to include this on every page.
this.ClientScript.RegisterStartupScript(this.GetType(), "ErrorMessage", strMessageToClient);
You'll need to pass the page into the function
SendErrorMessageToClient(Page page, string strErrorType, string strErrorMessage)
so that you can change
this.ClientScript...
to
page.ClientScript...
The reason being that ClientScript is part of the Page class
Or, possibly better, pass the ClientScript object, rather than page.
So your definition would look like
SendErrorMessageToClient(ClientScript clientScript, string strErrorType, string strErrorMessage) {
string strMessageToClient = "";
//Allow single quotes on client-side in JavaScript
strErrorMessage = strErrorMessage.Replace("'", "\\'");
strMessageToClient = String.Format("<script type='text/javascript' language='javascript'>alert('{0}\\n\\n{1}');</script>",
strErrorType, strErrorMessage);
clientScript.RegisterStartupScript(this.GetType(), "ErrorMessage", strMessageToClient);
}
Error: missing } in XML expression
source code: http://localhost:3811/Clinic/ScheduleModule/ManageWorkingTime.aspx?ScheduleId=FRXTn%2fX1N8Wy8C%2fdJqQmDjrOEECv%2fRwauMVX6ZTipAM%3d
line: 0, column: 188
code:
<script language='javascript'>$(document).ready(function() {Sexy.alert( "Can not copy files." );});</script>
CODE:
public static void ShowAsync(string sMessage, MessageBoxTypes sType, Control control, Page pPage)
{
StringBuilder sb = new StringBuilder();
sb.Append("<script language='javascript'>");
string sMsg = sMessage;
sMsg = sMsg.Replace("\n", "\\n");
sMsg = sMsg.Replace("\"", "'");
sb.Append(#"$(document).ready(function() {");
sb.Append(#"Sexy." + sType + #"( """ + sMsg + #""" );");
sb.Append(#"});");
sb.Append(#"</" + "script>");
ScriptManager.RegisterClientScriptBlock(pPage, typeof(Page), control.ClientID, sb.ToString(), true);
}
if i change true to false in RegisterClientScriptBlock then i get
error: $ is not defined
source code: http://localhost:3811/Clinic/ScheduleModule/ManageWorkingTime.aspx?ScheduleId=dH0ry1kng6MwGCRgCxXg8N5nCncbzPzn3TAOEI0tAY4%3d
line: 0
i call this popup like:
MessageBox.ShowAsync("Can not copy files.", MessageBoxTypes.alert, this, Page);
What can be wrong. If i copy this (JQUERY)
<script language='javascript'>$(document).ready(function() {Sexy.alert( "Can not copy files." );});</script>
into some .aspx page popup works. But if i call it from code behind and daypilot pro in this updatepanel form then i get this error.
Can be problem that two ajax framewroks mixed themself? How to prevent this?
i try with jquery.noConflict but it is the same
$.noConflict();
jQuery(document).ready(function() { Sexy.alert("Can not copy files."); });
Thx
If you change the last parameter in RegisterClientScriptBlock from true to false it will not add the script tag anymore. Currently with the setting to true, you have the script tag twice. Not sure what happens, but can't be good :-)
$ sounds like jquery? You don't mention what you are using? I mix ASP.NET Ajax with jquery and that works fine. What Version are you on?
I want to add StyleSheets programmatically in the head section but one of the examples I saw seemed to need to many lines of code to add just one style sheet even though I may need a lot:
Example Code:
HtmlLink css = new HtmlLink();
css.Href = "css/fancyforms.css";
css.Attributes["rel"] = "stylesheet";
css.Attributes["type"] = "text/css";
css.Attributes["media"] = "all";
Page.Header.Controls.Add(css);
I also use Page.Header.RenderControl() method but it didn't work either. Object null something error was thrown.
I also used Page.Header.InnerHtml and InnerText += "<link .... "/> things but they threw the Literal error which is I think common error.
I used this code :
List<Literal> cssFiles = new List<Literal>();
cssFiles.Add(new Literal() { Text = #"<link href=""" + ResolveUrl("~/Resources/Styles/MainMaster/MainDesign.css") + #""" type=""text/css"" rel=""stylesheet"" />" });
cssFiles.Add(new Literal() { Text = #"<link href=""" + ResolveUrl("~/Resources/Styles/MainMaster/MainLayout.css") + #""" type=""text/css"" rel=""stylesheet"" />" });
AddStyleRange(cssFiles);
private void AddStyleRange(List<Literal> cssFiles)
{
foreach (Literal item in cssFiles)
{
this.Header.Controls.Add(item);
}
}
It worked at first but when I change the pages it stopped working.
I am using Master Page and I am writing these codes on Master.cs file and also some people recommended to use this.Header instead of Page.Header but when I built it throws an error which says I cannot declare that like this.
It shouldn't be that hard to add many styles.
It is getting complicated.
Okay, here is the solution I am currently using :
I created a helper class :
using System.Web.UI;
using System.Web.UI.WebControls;
namespace BusinessLogic.Helper
{
public class CssAdder
{
public static void AddCss(string path, Page page)
{
Literal cssFile = new Literal() { Text = #"<link href=""" + page.ResolveUrl(path) + #""" type=""text/css"" rel=""stylesheet"" />" };
page.Header.Controls.Add(cssFile);
}
}
}
and then through this helper class, all I have to do is :
CssAdder.AddCss("~/Resources/Styles/MainMaster/MainDesign.css", this.Page);
CssAdder.AddCss("~/Resources/Styles/MainMaster/MainLayout.css", this.Page);
CssAdder.AddCss("~/Resources/Styles/Controls/RightMainMenu.css", this.Page);
//...
So I can add as much as I want with one line of simple code.
It also works with Masterpage and content page relationships.
Hope it helps.
P.S: I don't know the performance difference between this and other solutions but it looks more elegant and easy to consume.
I'll paste the thing which worked for me:
HtmlLink link = new HtmlLink();
//Add appropriate attributes
link.Attributes.Add("rel", "stylesheet");
link.Attributes.Add("type", "text/css");
link.Href = "/Resources/CSS/NewStyles.css";
link.Attributes.Add("media", "screen, projection");
//add it to page head section
this.Page.Header.Controls.Add(link);
Even I searched a lot on this, I'd to add a overriding style sheet when a button is clicked. I used the above code and it worked perfectly to me.
I define a generic HTML <link> and set the href attribute programmatically.
For example, in the page <head> I have:
<link id="cssStyle" runat="server" rel="stylesheet" type="text/css" />.
Then in Page_Load set the Href property of cssStyle:
cssStyle.Href = "path/to/Styles.css";
Seems a bit cleaner with the upside of having the design control over placing the <link> in the desired order.
I went a step over, I wanted a method that makes me impossible to add include duplicates, something like ClientScriptManager.RegisterClientScriptInclude().
The solution is to give an ID to the control added in the Header section.
if (!String.IsNullOrEmpty(Key))
if (Page.Header.FindControl(Key) != null) return;
HtmlLink link = new HtmlLink();
if (!String.IsNullOrEmpty(Key)) link.ID = Key;
link.Href = StyleUrl;
link.Attributes.Add("type", "text/css");
link.Attributes.Add("rel", "stylesheet");
Page.Header.Controls.Add(link);
For the complete article I wrote: http://www.idea-r.it/Blog.aspx?Article=49
I have a project that I am working on in VS2005. I have added a WebBrowser control. I add a basic empty page to the control
private const string _basicHtmlForm = "<html> "
+ "<head> "
+ "<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/> "
+ "<title>Test document</title> "
+ "<script type='text/javascript'> "
+ "function ShowAlert(message) { "
+ " alert(message); "
+ "} "
+ "</script> "
+ "</head> "
+ "<body><div id='mainDiv'> "
+ "</div></body> "
+ "</html> ";
private string _defaultFont = "font-family: Arial; font-size:10pt;";
private void LoadWebForm()
{
try
{
_webBrowser.DocumentText = _basicHtmlForm;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and then add various elements via the dom (using _webBrowser.Document.CreateElement). I am also loading a css file:
private void AddStyles()
{
try
{
mshtml.HTMLDocument currentDocument = (mshtml.HTMLDocument) _webBrowser.Document.DomDocument;
mshtml.IHTMLStyleSheet styleSheet = currentDocument.createStyleSheet("", 0);
TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"basic.css"));
string style = reader.ReadToEnd();
styleSheet.cssText = style;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is the css page contents:
body {
background-color: #DDDDDD;
}
.categoryDiv {
background-color: #999999;
}
.categoryTable {
width:599px; background-color:#BBBBBB;
}
#mainDiv {
overflow:auto; width:600px;
}
The style page is loading successfully, but the only elements on the page that are being affected are the ones that are initially in the page (body and mainDiv). I have also tried including the css in a element in the header section, but it still only affects the elements that are there when the page is created.
So my question is, does anyone have any idea on why the css is not being applied to elements that are created after the page is loaded? I have also tried no applying the css until after all of my elements are added, but the results don't change.
I made a slight modification to your AddStyles() method and it works for me.
Where are you calling it from? I called it from "_webBrowser_DocumentCompleted".
I have to point out that I am calling AddStyles after I modify the DOM.
private void AddStyles()
{
try
{
if (_webBrowser.Document != null)
{
IHTMLDocument2 currentDocument = (IHTMLDocument2)_webBrowser.Document.DomDocument;
int length = currentDocument.styleSheets.length;
IHTMLStyleSheet styleSheet = currentDocument.createStyleSheet(#"", length + 1);
//length = currentDocument.styleSheets.length;
//styleSheet.addRule("body", "background-color:blue");
TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "basic.css"));
string style = reader.ReadToEnd();
styleSheet.cssText = style;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is my DocumentCompleted handler (I added some styles to basic.css for testing):
private void _webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement element = _webBrowser.Document.CreateElement("p");
element.InnerText = "Hello World1";
_webBrowser.Document.Body.AppendChild(element);
HtmlElement divTag = _webBrowser.Document.CreateElement("div");
divTag.SetAttribute("class", "categoryDiv");
divTag.InnerHtml = "<p>Hello World2</p>";
_webBrowser.Document.Body.AppendChild(divTag);
HtmlElement divTag2 = _webBrowser.Document.CreateElement("div");
divTag2.SetAttribute("id", "mainDiv2");
divTag2.InnerHtml = "<p>Hello World3</p>";
_webBrowser.Document.Body.AppendChild(divTag2);
AddStyles();
}
This is what I get (modified the style to make it as ugly as a single human being can hope to make it :D ):
one solution is to inspect the html prior to setting the DocumentText and inject CSS on the client side. I don't set the control url property but rather get the HTML via WebCLient and then set the DocumentText. maybe setting DocumentText (or in your case Document) after you manipulate the DOM could get it to re-render properly
private const string CSS_960 = #"960.css";
private const string SCRIPT_FMT = #"<style TYPE=""text/css"">{0}</style>";
private const string HEADER_END = #"</head>";
public void SetDocumentText(string value)
{
this.Url = null; // can't have both URL and DocText
this.Navigate("About:blank");
string css = null;
string html = value;
// check for known CSS file links and inject the resourced versions
if(html.Contains(CSS_960))
{
css = GetEmbeddedResourceString(CSS_960);
html = html.Insert(html.IndexOf(HEADER_END), string.Format(SCRIPT_FMT,css));
}
if (Document != null) {
Document.Write(string.Empty);
}
DocumentText = html;
}
It would be quite hard to say unless you send a link of this.
but usually the best method for doing style related stuff is that you have the css already in the page and in your c# code you only add ids or classes to elements to see the styles effects.
I have found that generated tags with class attribute does not get their styles applied.
This is my workaround that is done after the document is generated:
public static class WebBrowserExtensions
{
public static void Redraw(this WebBrowser browser)
{
string temp = Path.GetTempFileName();
File.WriteAllText(temp, browser.Document.Body.Parent.OuterHtml,
Encoding.GetEncoding(browser.Document.Encoding));
browser.Url = new Uri(temp);
}
}
I use similiar control instead of WebBrowser, I load HTML page with "default" style rules and I change the rules within the program.
(DrawBack - maintainance, when I need to add a rule, I also need to change it in code)
' ----------------------------------------------------------------------
Public Sub mcFontOrColorsChanged(ByVal isRefresh As Boolean)
' ----------------------------------------------------------------------
' Notify whichever is concerned:
Dim doc As mshtml.HTMLDocument = Me.Document
If (doc.styleSheets Is Nothing) Then Return
If (doc.styleSheets.length = 0) Then Return
Dim docStyleSheet As mshtml.IHTMLStyleSheet = CType(doc.styleSheets.item(0), mshtml.IHTMLStyleSheet)
Dim docStyleRules As mshtml.HTMLStyleSheetRulesCollection = CType(docStyleSheet.rules, mshtml.HTMLStyleSheetRulesCollection)
' Note: the following is needed seperately from 'Case "BODY"
Dim docBody As mshtml.HTMLBodyClass = CType(doc.body, mshtml.HTMLBodyClass)
If Not (docBody Is Nothing) Then
docBody.style.backgroundColor = colStrTextBg
End If
Dim i As Integer
Dim maxI As Integer = docStyleRules.length - 1
For i = 0 To maxI
Select Case (docStyleRules.item(i).selectorText)
Case "BODY"
docStyleRules.item(i).style.fontFamily = fName ' "Times New Roman" | "Verdana" | "courier new" | "comic sans ms" | "Arial"
Case "P.myStyle1"
docStyleRules.item(i).style.fontSize = fontSize.ToString & "pt"
Case "TD.myStyle2" ' do nothing
Case ".myStyle3"
docStyleRules.item(i).style.fontSize = fontSizePath.ToString & "pt"
docStyleRules.item(i).style.color = colStrTextFg
docStyleRules.item(i).style.backgroundColor = colStrTextBg
Case Else
Debug.WriteLine("Rule " & i.ToString & " " & docStyleRules.item(i).selectorText)
End Select
Next i
If (isRefresh) Then
Me.myRefresh(curNode)
End If
End Sub
It could be that the objects on the page EXIST at the time the page is being loaded, so each style can be applied. just because you add a node to the DOM tree, doesnt mean that it can have all of its attributes manipulated and rendered inside of the browser.
the methods above seem to use an approach the reloads the page (DOM), which suggests that this may be the case.
In short, refresh the page after you've added an element
It sounds as though phq has experienced this. I think the way I would approach is add a reference to jquery to your html document (from the start).
Then inside of the page, create a javascript function that accepts the element id and the name of the class to apply. Inside of the function, use jquery to dynamtically apply the class in question or to modify the css directly. For example, use .addClass or .css functions of jquery to modify the element.
From there, in your C# code, after you add the element dynamically invoke this javascript as described by Rick Strahl here: http://www.west-wind.com/Weblog/posts/493536.aspx
I got a user control which implements a reference to a css file, now I want to use this user control many times on page, and this will lead to duplication of inclusion of the css file.
With javascript files it is simple by using the ScriptManager.
So what is your suggestion for a solution or similar approach to the ScriptManager?
Here's a technique I've used before, although it may not be the best one:
Dim cssLink As String = String.Format("<link rel='stylesheet' type='text/css' href='{0}/css/cssLink.css' />", Request.ApplicationPath)
If (From c As LiteralControl In Page.Header.Controls.OfType(Of LiteralControl)() Where c.Text = cssLink).Count = 0 Then
Page.Header.Controls.Add(New LiteralControl(cssLink))
End If
As q is tagged c# thought I may as well paste in c# version from helper class:
public static void AddStyleLink(string href)
{
Page page = (Page)HttpContext.Current.CurrentHandler;
var existing =
(from c
in page.Header.Controls.OfType<HtmlGenericControl>()
where c.Attributes["href"] == href
select c).FirstOrDefault();
if (existing == null)
{
HtmlGenericControl link = new HtmlGenericControl("link");
link.Attributes.Add("rel", "stylesheet");
link.Attributes.Add("href", href);
page.Header.Controls.Add(link);
}
}
There is no easy way to check if the styles are registered to the page like ClientScript utility.
If you register your styles as an external css file to page like that :
HtmlLink link = new HtmlLink();
link.Href = relativePath;
link.Attributes["type"] = "text/css";
link.Attributes["rel"] = "stylesheet";
Page.Header.Controls.Add(link);
You can then check if it exists by looping the page header's Controls collection and looking for the path of the CSS file.