I've built a custom server control that uses custom CSS. The problem that I have is that I have to set a reference to the css file on each page I use the control.
Can I set this reference inside the control ? So that I could just add the control and not worry about the reference.
You need to follow the below steps to add the css/javascript/image in the web control itself.
Modify the AssemblyInfo.cs file, to add the web resource
[assembly: System.Web.UI.WebResource("CustomControls.Styles.GridStyles.css", "text/css"), PerformSubstitution = true)]
Adding the required files(css/javascript/images) to the custom server control solution. Note that we can add folders in the solution and just add separate it using '.'(dot)
More importantly, we should change the BuildAction Property from Content to Embedded Resource of the newly added css/javascript/image files.
Further we should load the stored resources from the DLL. Best event for this would be OnPreRender
Below is the sample code rendering css
protected override void OnPreRender(EventArgs e)
{
bool linkIncluded = false;
foreach (Control c in Page.Header.Controls)
{
if (c.ID == "GridStyle")
{
linkIncluded = true;
}
}
if (!linkIncluded)
{
HtmlGenericControl csslink = new HtmlGenericControl("link");
csslink.ID = "GridStyle";
csslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl(this.GetType(), "CustomControls.Styles.GridStyles.css"));
csslink.Attributes.Add("type", "text/css");
csslink.Attributes.Add("rel", "stylesheet");
Page.Header.Controls.Add(csslink);
}
}
Similarly for Adding javascript
protected override void OnPreRender(EventArgs e)
{
string resourceName = "CustomControls.GridViewScript.js";
ClientScriptManager cs = this.Page.ClientScript;
cs.RegisterClientScriptResource(this.GetType(), resourceName);
}
Similarly using the Added Image in CSS file. Use the below code
background: url('<%=WebResource("CustomControls.Styles.Cross.png")%>') no-repeat 95% 50%;
Thanks.
Here what I use to add css reference to Page programmatically :
HtmlLink link = new HtmlLink();
link.Href = relativePath;
link.Attributes["type"] = "text/css";
link.Attributes["rel"] = "stylesheet";
Page.Header.Controls.Add(link);
Maybe you should add some code to check if the css file added to the header control.
If you want build webcontrol, that will be reusable and in one assembly with css, js and other resources, than you can use WebResources
Working with Web Resources in ASP.NET 2.0
You could do it with a ScriptManager - and this will also help you embed the stylesheet in the custom control library's DLL.
Or you could just reference the CSS from your master page. Unless you're packging a custom control library to sell etc, ScriptManager is a LOT of extra effort vs the Master Page solution
I would think you could add Canavar's code to a base class that would be included with all the classes that need it.
public class myclass : BaseClass
{
var customCSS = customcss();
Page.Header.Controls.Add(customCSS); }
and your baseclass:
public class BaseClass : Page
{
public HtnlLink customcss(){
HtmlLink link = new HtmlLink();
link.Href = relativePath;
link.Attributes["type"] = "text/css";
link.Attributes["rel"] = "stylesheet";
return link;
}
}
or you could go down the route of
myObject.Attributes.Add("style","width:10px; height:100px;");
or
myObject.Attributes.Add("style",customStyle(););
where this is in your baseclass
public String customStyle()
{
return "width:10px; height:20px;";
}
and customstyle would be a function like so:
But I would assume that you use CSS for the rest of your site, so maybe a style could just be added to your stylesheet that you use on all pages through this method you could use the below code:
myObject.Attributes.Add("class","customControl");
This will then reference the correct CSS style from your main, always included stylesheet.
Unless I am missing something here....
Related
This is the code in my MasterPage:
<li id="liABOUT" runat="server">ABOUT</li>
When I am on another page referencing the MasterPage I want to add a class to this li control, something like this. Cant get it to work. Using ASP.NET 4.5
Me.Master.FindControl("ContentPlaceHolderMaster").FindControl("LiAbout").Attributes.Add("class", "active")
VB.NET or C# Code would be fine
You can create a public property in your MasterPage :
public String LiAboutClass
{
get { return liABOUT.Attributes["class"]; }
set { liABOUT.Attributes["class"] = value; }
}
Access this property in your ContentPage:
var siteMaster = (SiteMaster)this.Master;
if (siteMaster != null) siteMaster.LiAboutClass = "active";
Edit: Also you can use MasterType. it allows you to access the MasterTypes properties directly.
This works for me. I first converted it to HtmlGenericControl and then added attribute.
(Master.FindControl("liABOUT") as HtmlGenericControl).Attributes.Add("class", "active");
This worked....
' Get reference to control located on master page
Dim lb As HtmlGenericControl = Page.Master.FindControl("liABOUT")
lb.Attributes.Add("class", "active")
I have a custom control. It has an image. I have exposed the ImageURL attribute in the custom control code by creating a new attribute called ButtonIconImgSrc as follows:
[Category("Appearance")]
[Description("Gets or sets the logo image path")]
public String ButtonIconImgSrc
{
get
{
EnsureChildControls();
return iconImg.ImageUrl;
}
set
{
if (value != null)
{
iconImg.ImageUrl = value.ToString();
}
}
}
I compile the customeControl code to create a dll and then add the dll to my web site solution so i can drag and drop it onto my designer view or dynamically create it. Everything seems to work great in designer, i drop it on, set my custom atributes and looks good.
..... but the img does not show when i compile and run the site in a browser. nothing gets set correctly, its all lost by the time it gets back to the calling code - labels and textboxes and widths and heights etc. I want to create this customcontrol dynamically, not use the designer but same issue.
Below is the code that calls the above 'set' method, except after it comes back from th eset method its still blank.
protected void Page_Load(object sender, EventArgs e)
{
myCustomButton tb = new myCustomButton();
tb.ButtonIconImgSrc = "~/imgs/target_logo.png";
pnlButtons.Controls.Add(tb);
}
I see the code above being hit and the string "~/imgs/ibc_foh.png" being set in the myCustomButton code and that code exits and everything looks good. When the debugger gets back to the calling class (my websites Page_Load) the attribute tb.ButtonIconImgSrc is still blank, "". And so the image does not appear.
Updated: problem solved. I misunderstood the lifecycle of the control, the image was being overwritten in the createChildControls method
Create/Add a Generic HttpHandler page to your project.
in the function 'ProcessRequest'. there will be a HttpContext object (called context).
do as followed:
public class YouHandlerPage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// REVIEW AND PROCESS THE REQUEST (i.e. ...
// context.Request.QueryString
// context.Request.RequestContext.RouteData.Values;
// context.Request.Form
string fDirectory = #"C:\Users\john\Desktop\";
string fileName = "ibc";
string fileExt = "png";
context.Response.StatusCode = 200;
context.Response.ContentType = "Image/" + fileExt;
//let context.Response.ContentLength be specified by the following WriteFile method
context.Response.WriteFile(Format.String("{0}{1}.{2}", fDirectory, fileName, fileExt));
}
public bool IsReusable { get { return false;} }
}
now, run your web application.. and goto localhost:<portassigned>/<handlerpagefilename>.ashx
Where locahost:<portassigned> is your domain (or IIS Express assigned), and <handlerpagefilename> is whatever your named you added GenericHandlerPage (which should end with .ashx).
When you visit this page, you should get your image..
Further Review
review Registering Routes to map to your HandlerPage.
review HttpModules as an alternative to httphandler pages
problem solved. I misunderstood the lifecycle of the control, the image was being overwritten in the createChildControls method
I have a page which initially inherited from MastePage.master . And I want to use the same page but with different masterpage(MasterPage2.master) at some other place in my project. For that I am using the following code.
private void Page_PreInit(object sender, EventArgs e)
{
if (Request.QueryString["Update"].ToString() == "New")
{
this.MasterPageFile = "MasterPage2.master";
Content con = new Content();
con = (Content)this.FindControl("Content1");
this.Content1.ContentPlaceHolderID = "ContentPlaceHolder2";
}
}
I am also trying to set the asp content tag's ContentPlaceHolderID to ContentPlaceHolder2 which is from MasterPage2.master. Initially it was ContentPlaceHolder1.
But I am getting null value at con = (Content)this.FindControl("Content1");
Thanks
Page internally stores in private '_contentTemplateCollection' hashtable. it uses ContentPlaceHolderID property as key and stores special class (that will be used to build/initialize Content tag) as a value
- so to change ContentPlaceHolderID value (defined within markup) you need to modify this hashtable, remove old entry linked with old Id and add other entry with new Id
- you need to change ContentPlaceHolderId before creating master page otherwise an exception will be thrown in runtime
- best place to change Ids is Page 'preinit' event and if it is better to change Ids before change master page (if you will change master page at runtime)
To change ContentPlaceHolderID of Content tag, you can use following function in Page PreInit event
public static void AssignContentToNewPlaceHoldersWithinPage(Page pPage, string pOldId, string pNewId)
{
if (pPage == null || string.IsNullOrEmpty(pOldId) || string.IsNullOrEmpty(pNewId))
{
return;
}
// Try to get a reference to private hashtable using fasterflect free reflection library in codeplex (http://fasterflect.codeplex.com/)
// you can replace following line with standard reflection APIs
var lTmpObj = pPage.TryGetFieldValue("_contentTemplateCollection");
if (lTmpObj != null && lTmpObj is Hashtable)
{
var _contentTemplateCollection = lTmpObj as Hashtable;
if (_contentTemplateCollection.ContainsKey(pOldId) && !_contentTemplateCollection.ContainsKey(pNewId))
{
var lTemplate = _contentTemplateCollection[pOldId];
_contentTemplateCollection.Add(pNewId, lTemplate);
_contentTemplateCollection.Remove(pOldId);
}
}
}
function parameter are
pPage is reference to page instance contains content tag
pOldId is ContentPlaceHolderId property value in markup - the Id you want to change
pNewId is the new Id you want to use
I hope that my answer will be useful and I am sorry if my English language is not good
You can dynamically change the Master Page at runtime, but you need to use the same ContentPlaceHolder IDs. That way, your pages will work with either Master Page without adding extra code to change the IDs at runtime.
private void Page_PreInit(object sender, EventArgs e)
{
if (Request.QueryString["Update"].ToString() == "New")
{
this.MasterPageFile = "MasterPage2.master";
}
}
You can even test that your page will work with either Master Page in the Visual Studio design/markup view by changing the MasterPageFile in the <% Page %> directive in the .aspx markup.
The Master Page can be changed by overriding OnPreInit.
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
MasterPageFile = "~/MasterPages/MyOther.Master";
}
But for the ContentPlaceHolders I would suggest to create new ContentPlaceHolders with the same name in both of your MasterPages.
I built custom ASP.NET control and it's working fine when I add it manually (drag and drop) or by code to controls in markup.
The custom control, MsgBox, had resources like JavaScript, CSS and images embedded in and the problem appeared when I tried to Render the control in class to return its HTML code, the Page instance is null and the "GetWebResourceUrl" needs it:
Page.ClientScript.GetWebResourceUrl(.....)
is there any way to get the resourceurl ? Here is my render code:
protected override void RenderContents(HtmlTextWriter writer)
{
using (PlaceHolder plh = new PlaceHolder())
{
if (Page != null)
{
if (DesignMode || Page.Header == null)
RegisterCSSInclude(plh);
}
HtmlGenericControl container = new HtmlGenericControl("div");
container.EnableViewState = false;
container.InnerHtml = "Control html code";
plh.Controls.Add(container);
plh.RenderControl(writer);
}
}
RegisterCSSInclude is method to register my css files:
private void RegisterCSSInclude(Control target)
{
// CSS
bool linkIncluded = false;
foreach (Control c in target.Controls)
{
if (c.ID == "MsgBxStyle")
{
linkIncluded = true;
}
}
if (!linkIncluded)
{
HtmlGenericControl globalCsslink = new HtmlGenericControl("link");
globalCsslink.ID = "MsgBxGStyle";
globalCsslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl(typeof(MessageBoxCtrl), "MessageBox.MsgBxStyles.WeDevMsgBox.css"));
globalCsslink.Attributes.Add("type", "text/css");
globalCsslink.Attributes.Add("rel", "stylesheet");
globalCsslink.EnableViewState = false;
target.Controls.Add(globalCsslink);
HtmlGenericControl csslink = new HtmlGenericControl("link");
csslink.ID = "MsgBxStyle";
csslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl(typeof(MessageBoxCtrl), "MessageBox.MsgBxStyles." + Style.ToString().ToLower() + ".css"));
csslink.Attributes.Add("type", "text/css");
csslink.Attributes.Add("rel", "stylesheet");
csslink.EnableViewState = false;
target.Controls.Add(csslink);
}
}
Update:
PS: I'm tring to use control in generic handler (ashx) where I call ShowMsgBox method which is a method in a class and not in a page or user control.
ShowMsgBox method should create an instance of MsgBox control and render it then return the html code to ashx class :
var htmlCode = MyClass.ShowMsgBox("myMsg");
context.Response.write(htmlCode);
I built a custom ASP.NET control ...
I'm tring to use control in generic handler (ashx) ... not in a page or user control.
A Page is a handler. You want to use a convenience provided by the Page class, but you don't want to inherit from Page. The niceties of Page, such as ClientScript, expect a Page from which to get various information.
You can provide a dummy Page object to your control by setting the Page property of your custom Control:
this.Page = new Page();
...then you will need to set various properties (assuming they are public) which are expected by ClientScriptManager.GetWebResourceUrl():
this.Page.Foo = "bar";
then you can call:
this.Page.ClientScript.GetWebResourceUrl(...);
If this is the specific class that inherits from WebControl page shouldn't be null. If its another class that you are rendering as part of a hierarchy you can add a parameter of type Page and pass the reference of the current page to it.
i wrote a page (only class that derives from System.Web.UI.Page, that i want to use in more websites. I dynamically add webcontrols to Page.Controls collection like this:
Panel p = new Panel();
p.Style.Add("float", "left");
p.Controls.Add(locLT);
Page.Controls.Add(p);
this code renders only
<div style="float:left;">
</div>
How can i add HTML, HEADER and BODY section without manually write this? Is it possible?
I recommend MasterPages but you can do this:
public class CustomBase : System.Web.UI.Page
{
protected override void Render( System.Web.UI.HtmlTextWriter textWriter )
{
using (System.IO.StringWriter stringWriter = new System.IO.StringWriter())
{
using (HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter))
{
LiteralControl header =new LiteralControl();
header.Text = RenderHeader(); // implement HTML HEAD BODY...etc
LiteralControl footer = new LiteralControl();
footer.Text = RenderFooter(); // implement CLOSE BODY HTML...etc
this.Controls.AddAt(0, header); //top
this.Controls.Add(footer); //bottom
base.Render(htmlWriter);
}
}
textWriter.Write(stringWriter.ToString());
}
}
I don't believe there is any way to automatically generate the tags, but you can create your own Render method that outputs the required basic HTML framework.
Before using MasterPages a common way to add header and footer for a page was to inherit from a BasePage like http://gist.github.com/214437 and from the BasePage load header and footer controls. I think that a MasterPage is better choice for you than the BasePage above. One of the drawbacks with a MasterPage is that you have to add asp:content at every page but it's still better than the old way.
If your "page" is completely dynamic and has no aspx front-end (I didn't realize this was possible?!)... then what you really want is probably a custom HttpHandler rather than inheriting from Page.