I have created a custom web control to act as a button with an image. I would like to be able to set this as the target of the DefaultButton
parameter of an ASP.NET Panel control. I have implemented the IButton interface, and no error is generated when loading the page using the control. However, when I press enter in a textbox within that panel, the Click event of the control is not raised. When I replace my control with a standard ASP.NET button, everything works fine.
I have a test page with a panel containing a textbox, an instance of my custom button, and a standard asp.net button. The buttons are wired to an event handler which will change the textbox to the ID of the caller.
When DefaultButton of the panel is set to the ASP.NET button, hitting enter in the next box works correctly - the page posts back, and the text box is populated with the name of the standard button. When DefaultButton of the panel is set to my button, hitting enter in the textbox causes the page to postback, but the Click event is not fired. Clicking the button manually works correctly.
Does anyone know what I have to add to my custom control to make it handle the event coming from the Panel control? I'm looking using Reflector at the source code for Button, but cannot identify what is enabling this behaviour.
I have posted the source of the control below, and the relevant source of the test page.
Control Source:
public class NewButton : WebControl, IPostBackEventHandler, IButtonControl
{
public NewButton() : base(HtmlTextWriterTag.A) { }
public event EventHandler Click;
public event CommandEventHandler Command;
public string Text
{
get { return ViewState["Text"] as string; }
set { ViewState["Text"] = value; }
}
public string ImageUrl
{
get { return ViewState["ImageUrl"] as string; }
set { ViewState["ImageUrl"] = value; }
}
protected virtual void OnClick(EventArgs e)
{
if (Click != null)
Click(this, e);
}
protected virtual void OnCommand(CommandEventArgs e)
{
if (Command != null)
Command(this, e);
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Class, "Button");
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(this, "Click"));
}
protected override void RenderContents(HtmlTextWriter writer)
{
// base.RenderContents(writer);
writer.WriteFullBeginTag("span");
writer.WriteFullBeginTag("span");
if (!String.IsNullOrEmpty(ImageUrl))
{
writer.WriteBeginTag("img");
writer.WriteAttribute("src", Page.ResolveClientUrl(ImageUrl));
writer.Write(HtmlTextWriter.SelfClosingTagEnd);
writer.Write(" ");
}
writer.WriteEncodedText(Text);
writer.WriteEndTag("span");
writer.WriteEndTag("span");
}
public void RaisePostBackEvent(string eventArgument)
{
if (this.CausesValidation)
{
Page.Validate(this.ValidationGroup);
}
OnClick(EventArgs.Empty);
OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}
public bool CausesValidation
{
get { return ViewState["CausesValidation"] as bool? ?? true; }
set { ViewState["CausesValidation"] = value; }
}
public string CommandArgument
{
get { return ViewState["CommandArgument"] as string; }
set { ViewState["CommandArgument"] = value; }
}
public string CommandName
{
get { return ViewState["CommandName"] as string; }
set { ViewState["CommandName"] = value; }
}
public string PostBackUrl
{
get { return ViewState["PostBackUrl"] as string; }
set { ViewState["PostBackUrl"] = value; }
}
public string ValidationGroup
{
get { return ViewState["ValidationGroup"] as string; }
set { ViewState["ValidationGroup"] = value; }
}
}
Code to call it:
<asp:Panel ID="Panel1" runat="server" CssClass="StandardForm" DefaultButton="NewButton1">
<asp:TextBox runat="server" ID="text1" Columns="40" />
<MyControls:NewButton ID="NewButton1" runat="server" Text="Test" OnClick="OnClick" />
<asp:Button runat="server" ID="OldButton1" OnClick="OnClick" Text="Test" />
</asp:Panel>
Code Behind:
protected void OnClick(object sender, EventArgs args)
{
text1.Text = "Click event received from " + ((WebControl) sender).ID;
}
The control renders as follows:
<div id="ctl00_MainContent_Panel1" class="StandardForm" onkeypress="javascript:return WebForm_FireDefaultButton(event, 'ctl00_MainContent_NewButton1')">
<input name="ctl00$MainContent$text1" type="text" size="40" id="ctl00_MainContent_text1" />
<a id="ctl00_MainContent_NewButton1" class="Button" onclick="__doPostBack('ctl00$MainContent$NewButton1','')"><span><span>Test</span></span></a>
<input type="button" name="ctl00$MainContent$OldButton1" value="Test" onclick="javascript:__doPostBack('ctl00$MainContent$OldButton1','')" id="ctl00_MainContent_OldButton1" />
</div>