Adding StyleSheets Programmatically in Asp.Net - c#

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

Related

Prevent HtmlAgilityPack from automatically adding unclosed tags

Goal : Remove Inline-styles and add class using Html-Agility-Pack in Razor html in MVC.
It's been a 2 days since trying to figure out a solution for parsing Razor html using Html-Agility-Pack
I do know that Html-Agility-Pack is not good for parsing razor. I know by applying logic into it, we can build this thing up, would need your help.
Problem : Html-Agility-Pack when encounters un-closed tags, it tries to add automatically tags in the HTML structure, what I need to achieve is Html-Agility-Pack should not add any extra tags after html is parsed.
Below is the problem I am facing, extra tags are added. It treats c# Type as a tag and adds in document.
<span>(#((Session["Usernames"] as List<Username>)[0].Name))</span>
<span>(#((Session["Usernames"] as List<Username>)[0].Name))</Username></span>
Code I tried below code but I cant find any options which will help in achieving this
var document = new HtmlDocument();
document.OptionCheckSyntax = false;
document.OptionWriteEmptyNodes = true;
document.OptionAutoCloseOnEnd = true;
document.LoadHtml(line);
var node = document.DocumentNode.SelectNodes("//*[#style]")[0];
if (node.Attributes["class"] != null)
{
var NodeClass = node.Attributes["class"].Value;
node.SetAttributeValue("class", NodeClass + " " + className);
}
else
{
node.Attributes.Add("class", className);
}

Add CSS File in DLL (Class Library)

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);

Using jQuery .load() with aspx

So I'm fairly new to the .NET framework, but what I'm trying to do is execute the following jQuery code:
$(document).on('click', 'a[data-link]', function () {
var $this = $(this);
url = $this.data('link');
$("#imagePreview").load("imageProcess.aspx?"+url);
where url holds something like "model=2k01&type=black&category=variable".
Unfortunately this doesn't work, becuase when I do something as simple as a Response.Write() in the aspx file, the div tag imagePreview doesn't do anything. However, removing the ? + url part works, but then I can't send any data over to the aspx file. I'm doing it this way because every link a[data-link] has different data that's being sent over, and I need to find a dynamic way to achieve this. Any suggestions would be much appreciated.
UPDATE:
Here is the part in my html code that is generating the url stuff:
<a class='modelsBlue' href = '#' data-link='model=" + $(this).find('model').text() + "&type=" + category + "'>" + $(this).find("model").text() + "</a>
and #image preview is in my code as:
<div id = "imagePreview"></div>
When I try to run the code above, i get the following error which seems to be coming from the jQuery.js file:
Microsoft JScript runtime error: Syntax error, unrecognized expression: &type=AutoEarly
Here is the imageProcess.aspx.cs file, which right now is just outputting all images in the directory:
namespace ModelMonitoring
{
public partial class imageProcess : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("test");
foreach (var f in Directory.GetFiles(Directory.GetCurrentDirectory()))
{
Response.Write(f);
Response.Write("<br />");
}
}
}
}
SECOND UPDATE:
I don't get the error running in chrome or firefox, but the files are not being output.
Turns out it was a whitespace issue. I had to add a wrapper around:
$(this).find('model').text()
to read:
$.trim($(this).find('model').text())
becuase the xml file I was reading from had whitespace around the model name. Thanks to anyone who replied!

C# WebBrowser control not applying css

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

Preventing the duplication of CSS files?

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.

Categories