TextBox
in an ASP.Net Web Forms application that posted back to the server when it was clicked on. We needed to support both the Click event style functionality and also the CommandName
- CommandArgument
functionality so that the TextBox
could be included in a DataGrid
and fire the DataGrid
's ItemCommand
event. It would not be necessary to read the value entered into the text box as it would be read only and be updated server side.The solution I came up with was to try and find a control that supported this functionality and that the server would think was a control of that type, but would be rendered in the browser as a
TextBox
. The best matching control was LinkButton
. LinkButton
provided all the server side functionality that I required, and little more, so I decided that I would subclass that control. Now all I had to do was make ASP render the control as a text box.Rather than do all the hard work myself, I thought that the easiest way to create the rendering code was to get the
LinkButton
to render itself to a dummy renderer, read in the string it rendered and then just change the bits I needed to. In order to get the control to look like a text box I have to change the element name to Input
and add a new attribute type="text"
. In order to get the value of the LinkButton
's Text property to display in the TextBox
I had to add value=""
. Finally to make the events fire when the TextBox
was clicked I had to assign the value of the href
attribute to the TextBox
's onclick
attribute. In order to get the events to fire when the user tabbed into the control I also added it to the onfocus
attribute.In order to not render the data part of the
LinkButton
in the ASP.Net page I overrode the RenderContents
method so that it did not do anything. Finally I removed all the re-useable code to another class so that I could use the technique again with other controls.Here is the final code...
public abstract class CustomLinkButton : LinkButton
{
protected abstract string GetInputType();
protected abstract void WriteControlSpecificAttributes(HtmlTextWriter writer);
public override void RenderBeginTag(HtmlTextWriter writer)
{
var builder = new StringBuilder();
using (var dummyWriter = new HtmlTextWriter(new StringWriter(builder)))
{
base.RenderBeginTag(dummyWriter);
var attributes = GetAttributes(builder.ToString());
foreach (var kvp in attributes)
{
if (kvp.Key == "href")
{
writer.AddAttribute("onClick", kvp.Value);
WritePostBackAttributes(writer, kvp.Value);
}
else
{
writer.AddAttribute(kvp.Key, kvp.Value);
}
}
writer.AddAttribute("type", GetInputType());
writer.AddAttribute("readonly", "readonly");
WriteControlSpecificAttributes(writer);
writer.RenderBeginTag("input");
}
}
protected virtual void WritePostBackAttributes(HtmlTextWriter writer, string hrefValue)
{
// do nothing
}
protected override void RenderContents(HtmlTextWriter writer)
{
// don't write anything
}
private Dictionary GetAttributes(string tag)
{
using (var reader = new XmlTextReader(tag, XmlNodeType.Element, null))
{
var result = new Dictionary();
reader.Read();
if (reader.MoveToFirstAttribute())
{
do
{
result[reader.Name] = reader.Value;
}
while (reader.MoveToNextAttribute());
}
return result;
}
}
}
public class NewTextBox : CustomLinkButton
{
protected override string GetInputType()
{
return "text";
}
protected override void WriteControlSpecificAttributes(HtmlTextWriter writer)
{
writer.AddAttribute("value", Text);
}
protected override void WritePostBackAttributes(HtmlTextWriter writer, string hrefValue)
{
writer.AddAttribute("onfocus", hrefValue);
}
}
No comments:
Post a Comment