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).
Related
I did the same modification on 3 kind of BaseValidator. I search a way to remove the duplicate code.
I did the same code for RequiredFieldValidator , RegularExpressionValidator and CustomValidator
Public Class CustomValidator
Inherits System.Web.UI.WebControls.CustomValidator
Protected Overrides Sub Render(writer As HtmlTextWriter)
Try
If Not String.IsNullOrWhiteSpace(ControlToValidate) Then
Dim ctv As Control = Me.FindControl(ControlToValidate)
writer.AddAttribute("for", ctv.ClientID)
End If
Catch
End Try
MyBase.Render(writer)
End Sub
Protected Overrides ReadOnly Property TagKey() As System.Web.UI.HtmlTextWriterTag
Get
Return HtmlTextWriterTag.Label
End Get
End Property
End Class
I ran into the same issue you have with these exact classes; I wanted to add some additional features to the validation controls. The way I ended up sharing some common code was implementing my own classes that inherited from the validator classes and then implementing the shared logic in a utility class. I'm not familiar with VB, so please bear with the C# example.
public static class ValidationUtilities
{
public static void AddFor(Control validationControl, string controlToValidate, HtmlTextWriter writer)
{
if (!string.IsNullOrWhiteSpace(controlToValidate))
{
var ctv = validationControl.FindControl(controlToValidate);
writer.AddAddtribute("for", ctv.ClientID);
}
}
}
class MyRegularExpressionValidator : RegularExpressionValidator
{
protected override void Render(HtmlTextWriter writer)
{
ValidationUtilities.AddFor(this, ControlToValidate, writer);
}
}
class MyRequiredFieldValidator : RequiredFieldValidator
{
protected override void Render(HtmlTextWriter writer)
{
ValidationUtilities.AddFor(this, ControlToValidate, writer);
}
}
You could make the argument that's more work than it's worth for not duplicating a small amount of code, but if you have a lot more, or your duplicated code is complex in some way, this is a way you can share it. Also, I made my utility class static, but there's no reason it couldn't be otherwise.
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.
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
I have my own Control1 which is dynamically added as child control to Control2 which implements INamingContainer in CreateChildControls() of control2.
Control1 itself implements IPostBackEventHandler. But RaisePostBackEvent() method is never called on Control1, despite I do call postback method from JavaScript.
And yes, there are other controls which implement IPostBackEventHandler interface on the page.
What did I miss?
What could cause the issue?
UPDATE: Control1 is always created exactly the same way and assigned exactly the same ID in Control2
it looks like this in Control2:
protected override void CreateChildControls()
{
if(!this.DesignMode)
{
Control1 c = new Control1();
c.ID = "FIXED_ID";
}
base.CreateChildControls();
}
UPDATE2:
Control1:
public class Control1: Control, IPostBackEventHandler
{
...
protected virtual void RaisePostBackEvent(string eventArgument)
{
if(!String.IsNullOrEmpty(eventArgument))
{
// Some other code
}
}
}
if I add line
Page.RegisterRequiresRaiseEvent(c);
In CreateChildControls() in Control2 then this method is being called but always with null eventArgument.
UPDATE3:
In JavaScript on some onClick event I do the following:
__doPostBack(Control1.UniqueID,'commandId=MyCommand');
where Control1.UniqueID is of course substituted with real uniqueID during rendering. I checked, this script is being called.
Can you show us the source code of first control? Anyway there is a simple example.
public class TestControl2 : CompositeControl
{
protected override void CreateChildControls()
{
base.CreateChildControls();
if (!DesignMode)
this.Controls.Add(new TestControl());
}
}
public class TestControl : WebControl, IPostBackEventHandler
{
public TestControl() : base(HtmlTextWriterTag.Input) { }
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "button");
writer.AddAttribute(HtmlTextWriterAttribute.Name, base.UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(this, null));
writer.AddAttribute(HtmlTextWriterAttribute.Value, "Submit Query");
}
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
// Raise post back event
}
}
Edit
Why you are generating the post back script out of the control and manually? You have to use Page.ClientScript.GetPostBackEventReference method. It generates and includes some necessary inline and embedded scripts to the page.
Why you are deriving your class from Control? It's good for those controls which don't have any user interface.
From MSDN
This is the primary class that you
derive from when you develop custom
ASP.NET server controls. Control does
not have any user interface (UI)
specific features. If you are
authoring a control that does not have
a UI, or combines other controls that
render their own UI, derive from
Control. If you are authoring a
control that does have a UI, derive
from WebControl or any control in the
System.Web.UI.WebControls namespace
that provides an appropriate starting
point for your custom control.
You have to derive your control from WebControl class as follows.
public class TestCtl : WebControl, IPostBackEventHandler
{
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
// Add onclick event.
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(this, "Arguments"));
}
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
throw new NotImplementedException();
}
}
I'm going to guess that it's the "dynamically added as child control to Control2" that is the issue, but without any code it's pretty hard to diagnose.
When during the page lifecycle are you dynamically adding it? Are you recreating the dynamic control in the exact same way, with the same ID, after the postback?
My inspiration for this question was my discovery of the very annoying default style (border-width: 0px;) on the ImageButton web control. The simple solution is to override it by adding your own style to the control e.g. Style="border-width: 2px;".
How every, it would have been nice to just make a simple control adapter that would just step in at the right place and just tell the control not to render the default styling.
After looking a bit at the code from the CSSFriendly ControlAdapter project, it seems like they are recreating much of the rendering, which is overkill for what I want to do -- i.e. just change the default styling that is rendered out.
So the question, how to just modify the rendering of the default styles through control adapters, and leave the rest as is?
Is it even possible?
Thanks, Egil.
There are two ways to do this. Both will require writing up a custom Control Adapter. Either you can set the actual value in code, or you can just not include the value at all and then use CSS to set your value. Here's the code you'll need to do this.
namespace TestApp
{
using System.IO;
using System.Web.UI;
using System.Web.UI.Adapters;
public class ImageAdapter : ControlAdapter
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(new RewriteImageHtmlTextWriter(writer));
}
public class RewriteImageHtmlTextWriter : HtmlTextWriter
{
public RewriteImageHtmlTextWriter(TextWriter writer)
: base(writer)
{
InnerWriter = writer;
}
public RewriteImageHtmlTextWriter(HtmlTextWriter writer)
: base(writer)
{
InnerWriter = writer.InnerWriter;
}
public override void AddAttribute(HtmlTextWriterAttribute key, string value, bool fEncode)
{
if (key == HtmlTextWriterAttribute.Border)
{
// change the value
//value = "2";
// -or-
// don't include the value
//return;
}
base.AddAttribute(key, value, fEncode);
}
public override void AddStyleAttribute(HtmlTextWriterStyle key, string value)
{
if (key == HtmlTextWriterStyle.BorderWidth)
{
// change the value
//value = "2px";
// -or-
// don't include the value
//return;
}
base.AddStyleAttribute(key, value);
}
}
}
}
Then you'll need to add an entry into one of your browser files like this
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.Image" adapterType="TestApp.ImageAdapter, TestApp" />
</controlAdapters>
</browser>
</browsers>