I'm creating a WebControl that is used in several of my ASP.NET pages. In one instance, I'd like to add some ad hoc style attributes such as Width and Float.
Since I can't anticipate which attributes will be needed in the future, I'd like the markup using the control to be able to add any random style. I've got the control so it supports standard styles like Color, Width, etc., but not Float.
Is there any way to allow such attributes to be specified in the markup and have them propagate through to the rendered control unchanged? I'd like not to have to create my own custom Float property and any other possible style that might be needed.
I tried just adding style="..." in the markup, but this is simply stripped out and does not appear anywhere in the rendered control.
My previous answer pertains to User Controls, my mistake!
For a WebControl you can over ride the AddAttributesToRender method.
The following seems to work quite well:
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string style
{
get
{
String s = (String)ViewState["style"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["style"] = value;
}
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
if(!string.IsNullOrEmpty(style))
{
writer.AddAttribute(HtmlTextWriterAttribute.Style, style);
}
}
EDIT: Changed public property to "style" to take advantage of intellisence.
I would add a CssClass property to your WebControl. This would allow any page that uses your control to supply its own look and feel.
It may not be what you are looking for but if you having a surrounding element you could apply the styles as a string as per the following:
.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs" Inherits="HubbInvestor.WebUserControl1" %>
<div style="<%=AdHocStyle%>">
Some Text:
<asp:Button ID="Button1" runat="server" Text="A Button" />
</div>
.ascx.cs
public partial class WebUserControl1 : System.Web.UI.UserControl
{
private string adHocStyle = string.Empty;
public string AdHocStyle
{
get { return adHocStyle; }
set { adHocStyle = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
of course you don't get any nice intellisense completion on the styles
Related
I am trying to set a label in master page from content page, not using FindControl. So, in master page I declared:
public partial class MainMasterPage : System.Web.UI.MasterPage
{
public string UserOfficeLabel
{
get { return lblUserOffice.Text; }
set { lblUserOffice.Text = value; }
}
public string OfficeLocationLabel
{
get { return lblOfficeLocation.Text; }
set { lblOfficeLocation.Text = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
....
}
}
"UserOfficeLabel" and "OfficeLocationLabel" are labels on master page. Then in content page (.aspx) I added the following directive under "Page" directive:
<%# MasterType VirtualPath="~/Main/MainMasterPage.master" %>
In conent page's code behind (.cs file) I try to access/set the label:
Master.UserOfficeLabel = ...
but UserOfficeLabel is not an option for Master (VS Intellisense does not list it as an option). When I add it anyway, it says "MainMasterPage.UserOfficeLabel is inaccessible to its protection level"
I think you can find what you are looking for here:
http://odetocode.com/blogs/scott/archive/2005/07/16/mastertype-in-asp-net-2-0.aspx.
In theory when you compile you should see the code below inside a partial class
Public Shadows ReadOnly Property Master() As otc
Get
Return CType(MyBase.Master,otcMaster)
End Get
End Property
I've done something like what you are trying by declaring a variable
Dim LocalMasterPageRef As MyMasterPageName
LocalMasterPageRef = CType(Me.Master, MyMasterPageName)
...
LocalMasterPageRef.xxxx
Hope it helps.
I have a user control on the master page and I would like to pass in a value into that user control from the subpage, how would I be able to pass the values?
This control is in the master page
<%# Register TagPrefix="test" TagName="Data" Src="controls/TEST.ascx" %>
This code variable is within the user control
public partial class Controls_TEST : System.Web.UI.UserControl
{
private string _Title;
public string Title
{
get { return _Title; }
set { _Title = value; }
}
}
Code within the subpage
public partial class sub_page : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Controls_Test m = LoadControl("~/Controls/TEST.ascx");
m.Title = "TEST";
}
}
Note the sample code within subpage does not work because it cannot find that user control within the subpage.
I've tried Page.Master.FindControl and it also does not work for me. PLease help.
Use properties to communicate from your Page to your MasterPage and use properties to communicate from your MasterPage to the UserControl.
To get a reference to the control in your MasterPage you should provide a public property that returns it:
For example(in MasterPage):
public Controls_Test MyControl
{
get
{
return Controls_TEST1;
}
}
And you can call this property from one of your ContentPages in this way(f.e. if your master's type is named "SiteMaster"):
protected void Page_Load(object sender, EventArgs e)
{
((SiteMaster)Page.Master).MyControl.Title = "TEST";
}
As a rule of thumb: the more you encapsulate your controls, the more robust ,failsafe, maintanable and extendable your code will be.
Hence it would be better to provide only access to the Title rather than to the whole UserControl.
In MasterPage:
public String Title
{
get
{
return Controls_TEST1.Title;
}
set
{
Controls_TEST1.Title = value;
}
}
In the ContentPage:
((SiteMaster)Page.Master).Title = "TEST";
On this way you could change the logic and controls in your UserControl and MasterPage without having problems in your pages that already have accessed the UserControl directly.
The following asp.net side code of control:
<asp:TextBox runat="server" ID="LimitTextBox" Text="20" ClientIDMode="Static" />
Generates such HTML-code:
<input name="ctl11$ctl00$ctl02$TeamPlayerSelector$LimitTextBox"
type="text" value="20" id="LimitTextBox">
ID attribute - as is required, but how can I remove 'name' attribute? It is not required for me and is also too long to transfer it to user browser.
How can I prevent 'name' attribute generation? Thanks
P.S. I work under ASP.NET 4.0
create a Filter (class that inherits from Stream), assign it to your HttpContext.Response.Filter attribute, and in it you would overwrite the Write method, to remove all the name-tags from the generated html :)
See this page for more information http://msdn.microsoft.com/en-us/library/system.web.httpresponse.filter.aspx
Update
Looking at the sourcecode for TextBox it reveals that Name is actually added to the Attributes-list during render, so it should be possible to interfere with the rendering of the TextBox class and prevent this attribute from being added. This should do
public class NoNamesTextBox : TextBox
{
private class NoNamesHtmlTextWriter : HtmlTextWriter
{
public NoNamesHtmlTextWriter(TextWriter writer) : base(writer) {}
public override void WriteAttribute(string name, string value, bool fEncode)
{
if (name.Equals("name", StringComparison.OrdinalIgnoreCase)) return;
base.WriteAttribute(name, value, fEncode);
}
}
protected override void Render(HtmlTextWriter writer)
{
var noNamesWriter = new NoNamesHtmlTextWriter(writer);
base.Render(noNamesWriter);
}
}
Update once more
How could i forget! You don't even need to subclass your textbox. In asp.net you can define which HtmlTextWriter type you want to use per control, so you can just configure that every TextBox control should use an instance of your own NoNamesHtmlTextWriter like this
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter
controlType="System.Web.UI.WebControls.TextBox"
adapterType="NoNamesTextBoxAdapter"
/>
</controlAdapters>
</browser>
</browsers>
public class NoNamesTextBoxAdapter : ControlAdapter
{
private class NoNamesHtmlTextWriter : HtmlTextWriter
{
public NoNamesHtmlTextWriter(TextWriter writer) : base(writer) { }
public override void WriteAttribute(string name, string value, bool fEncode)
{
if (name.Equals("name", StringComparison.OrdinalIgnoreCase)) return;
base.WriteAttribute(name, value, fEncode);
}
}
protected override void Render(HtmlTextWriter writer)
{
var noNamesRender = new HtmlTextWriter(writer);
base.Render(noNamesRender);
}
}
For some unknown reason the WriteAttribute override didn't work. I replaced it with:
public override void AddAttribute(HtmlTextWriterAttribute key, string value)
{
if (key == HtmlTextWriterAttribute.Name) return;
base.AddAttribute(key, value);
}
And it worked like a charm.
Also if you just need a custom Name you can just override the UniqueID property:
public class MyCustomControl : TextBox
{
public override string UniqueID
{
get
{
//return base.UniqueID;
return "test123";
}
}
}
Thanks for your help!
Setting EnableViewState="False" will slim down the name. You can also make a class that inherits the Textbox Control and override the Render procedure to not include the name.
Public Class CustomTextBox
Inherits TextBox
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.Render(writer)
'Simplified rendering of control...
writer.WriteLine("<input type='text' id='" & MyBase.ClientID & "'>")
End Sub
End Class
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim MyCustomTextBox As New CustomTextBox
form1.Controls.Add(MyCustomTextBox)
End Sub
Alternatively, if you don't want to have to add the control at run-time, you can make your CustomTextBox as a ServerControl so that you can add it at design time.
what ASP.Net controls render in name attributes, comes from UniqueID property. It's not necessarily good idea to override it, since ASP.NET uses that to locate control on postback to route postback data & events. However, if you are sure it is ok in your scenario, you certainly can override UniqueID property following #Pauli Østerø's answer. Have fun!
I think better is to change name property to same like ID is..
Just try bellow by using Jquery on document.ready(function(){})
document.ready(function(){
$.each($('div').children(), function() {
$(this).attr("name",$(this).attr("id"));
});
});
You can override the name property and return whatever you want (http://referencesource.microsoft.com/#System.Web/xsp/system/Web/UI/HtmlControls/HtmlInputControl.cs).
I have a user control which accepts a title attribute. I would also like that input inner HTML (ASP Controls also) inside of that user control tag like so:
<uc:customPanel title="My panel">
<h1>Here we can add whatever HTML or ASP controls we would like.</h1>
<asp:TextBox></asp:TextBox>
</uc:customPanel>
How can I achieve this? I have the title attribute working correctly.
Thanks.
Implement a class that extends Panel and implements INamingContainer:
public class Container: Panel, INamingContainer
{
}
Then, your CustomPanel needs to expose a property of type Container and another property of type ITemplate:
public Container ContainerContent
{
get
{
EnsureChildControls();
return content;
}
}
[TemplateContainer(typeof(Container))]
[TemplateInstance(TemplateInstance.Single)]
public virtual ITemplate Content
{
get { return templateContent; }
set { templateContent = value; }
}
Then in method CreateChildControls(), add this:
if (templateContent != null)
{
templateContent.InstantiateIn(content);
}
And you will be using it like this:
<uc:customPanel title="My panel">
<Content>
<h1>Here we can add whatever HTML or ASP controls we would like.</h1>
<asp:TextBox></asp:TextBox>
</Content>
</uc:customPanel>
You need to make sure EnsureChildControls is called. There are number of ways of doing that such as through the CreateChildControls base method but you can simply do this to get the inner contents of a custom control to render. It gets more complicated when you need to remember state and trigger events but for plain HTML this should work.
protected override void Render(HtmlTextWriter writer) {
EnsureChildControls();
base.Render(writer);
}
I want to be able to find the old value of a asp.net control (textbox, checkbox etc) without relying on events (e.g. OnTextChange event). Something like "someTextboxControl.OldText" would be perfect! I imagine that it is stored in the viewstate and need to somehow get at it via a custom control. Any ideas?
The answer provided by Shrage was helpful, but it took some additional searching to make this solution work. I placed his code into the code behind within the namespace of the page I was working on. Additionally I had to register the control, and change update the control in question.
Register extended textboxex control; this goes right below the page directive
<%# Register TagPrefix="group" Namespace="ESM_Web_Portal" Assembly="ESM Web Portal" %>
Update the texbox you want to extend in the aspx page
<group:TextBoxEx ID="txbEditPartNumber" runat="server" Text='<%# Bind("part_number") %>'></group:TextBoxEx>
Then in code behind I was able to use the extended TextBox control
protected void CheckForExistingPartNumber(object sender, ServerValidateEventArgs e)
{
CustomValidator cv = ((CustomValidator)sender);
TextBoxEx tb = (TextBoxEx)cv.Parent.FindControl(cv.ControlToValidate);
if (SupplyBLL.GetSupplyByPartNumber(e.Value) != null && tb.Text != tb.OldText)
{
e.IsValid = false;
}
}
public class TextBoxEx:System.Web.UI.WebControls.TextBox
{
public string OldText { get; set; }
protected override bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
OldText = Text;
return base.LoadPostData(postDataKey, postCollection);
}
}