WebControl Click Event Not Firing

D

Demetri

I have created a web control that can be rendered as either a linkbutton or a
button. It is a ConfirmButton control that allows a developer to force a user
to confirm if they intended to click it such as when they do a delete.

Everything is great. By and large it will be used in my repeater controls
using the command event when the user clicks on it and so that event is
working great.

My issue is the Click event. When the control is either in a repeater or by
itself on a page the click event does not fire. It never even gets raised by
the ConfirmButton control, never mind the listener (ie. page container).

Does anyone have a clue as to why the RaisePostBackEvent never fires? That
is my ultimate question here.

HTML output:

<input type="submit" name="Confirmbutton1" value="Go" id="Confirmbutton1"
onclick="return __doConfirm();__doPostBack('MyPage:Confirmbutton1','')" />

Page using the control event wiring:

private void InitializeComponent()
{
this.Confirmbutton1.Click += new
System.EventHandler(this.Confirmbutton1_Click);
this.Load += new System.EventHandler(this.Page_Load);

}


private void Confirmbutton1_Click(object sender, System.EventArgs e)
{
Response.Write("Click event fired!");
}

Server Control Code:

using System;
using System.Text;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web.UI.HtmlControls;
using System.Collections;

namespace WS.Ops.Web.CustomControls
{
/// <summary>
/// Button that provides a client-side confirmation prompt. It can be
either a Button or LinkButton.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:ConfirmButton1 runat=server></{0}:ConfirmButton1>"),
Description("Button that provides a client-side confirmation prompt. It can
be either a Button or LinkButton.")]
public class ConfirmButton : System.Web.UI.WebControls.WebControl,
IPostBackEventHandler
{
//the confirm button render types
public enum RenderTypes
{
LinkButton,
Button
};

#region Fields
private RenderTypes renderType = RenderTypes.LinkButton;
private WebControl controlToRender;
private const string CONFIRMSCRIPTKEY = "ConfirmScript";
private const string CONFIRMFUNCTIONNAME = "__doConfirm";
private string confirmationText = "Are you sure you want to continue?";
private string text = string.Empty;
private string navigateUrl = string.Empty;
private string commandArgument = string.Empty;
private string commandName = string.Empty;
private bool enableConfirmation = true;
private bool causesValidation = true;
private static readonly object EventCommand;
#endregion

#region Overrides
protected override void CreateChildControls()
{
base.CreateChildControls();

switch (RenderType)
{
default: // default is hyperlink
case RenderTypes.LinkButton:

LinkButton link = new LinkButton();
link.TabIndex = -1;
link.Text = this.Text;
link.Attributes.Add("href",Page.GetPostBackClientHyperlink(this,string.Empty));
link.Click += new EventHandler(this.OnClick);
link.Command += new CommandEventHandler(this.OnCommand);

if(EnableConfirmation)
link.Attributes.Add("onclick","return " + CONFIRMFUNCTIONNAME + "();");

controlToRender = link;

break;
case RenderTypes.Button:

Button button = new Button();
button.Text = this.Text;
button.Click += new EventHandler(this.OnClick);
button.Command += new CommandEventHandler(this.OnCommand);

if(EnableConfirmation)
button.Attributes.Add("onclick","return " + CONFIRMFUNCTIONNAME +
"();" + Page.GetPostBackEventReference(this,string.Empty));

controlToRender = button;

break;
}

//Copy control style attributes applied to this control
//to the control that will render
IEnumerator keys = this.Style.Keys.GetEnumerator();
while (keys.MoveNext())
{
string key = (string)keys.Current;
controlToRender.Style.Add(key, this.Style[key]);
}

//copy attributes applied to this control
//to the control that will render
IEnumerator attribKeys = this.Attributes.Keys.GetEnumerator();
while (attribKeys.MoveNext())
{
string key = (string)attribKeys.Current;
controlToRender.Attributes.Add(key, this.Attributes[key]);
}

if (this.CssClass != null && this.CssClass != string.Empty)
{
controlToRender.CssClass += " " + this.CssClass;
}

controlToRender.Enabled = this.Enabled;

controlToRender.ID = this.ID;
}

protected override void Render(HtmlTextWriter output)
{
EnsureChildControls(); //make sure child controls are created

//don't render this control, just the control chosen via
//the RenderType property
controlToRender.RenderControl(output);

}

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender (e);

//if enable confirmation then attach the
//confirm script to the page
if(EnableConfirmation)
{
RegisterConfirmationScript();
}
}

#endregion

#region Methods
private void RegisterConfirmationScript()
{
//only add the script to the page
//if it has not been added already
if(!Page.IsClientScriptBlockRegistered(CONFIRMSCRIPTKEY))
{
Page.RegisterClientScriptBlock(CONFIRMSCRIPTKEY,CreateJavaScriptFunction());
}
}

private string CreateJavaScriptFunction()
{
//build script string, the script is formatted for
//readability in view source
StringBuilder sb = new StringBuilder();
sb.Append("<script language=\"javascript\">" + Environment.NewLine);
sb.Append("\tfunction " + CONFIRMFUNCTIONNAME + "(){" +
Environment.NewLine);
sb.Append("\t\tvar agree = confirm(\"" + ConfirmationText + "\");" +
Environment.NewLine + Environment.NewLine);
sb.Append("\t\tif(agree){" + Environment.NewLine);
sb.Append("\t\t\treturn true;" + Environment.NewLine);
sb.Append("\t\t}" + Environment.NewLine + "else{" + Environment.NewLine);
sb.Append("\t\t\treturn false;" + Environment.NewLine);
sb.Append("\t\t}" + Environment.NewLine);
sb.Append("\t}" + Environment.NewLine);
sb.Append("</script>" + Environment.NewLine);

return sb.ToString();
}

protected virtual void OnClick(object sender, EventArgs e)
{
if(Click != null)
Click(this,e);
}

protected virtual void OnCommand(object sender,CommandEventArgs e)
{
CommandEventHandler handler =
(CommandEventHandler)base.Events[ConfirmButton.EventCommand];

if(handler != null)
handler(this,e);

base.RaiseBubbleEvent(this,e);
}
#endregion

#region Properties
/// <summary>
/// Gets or sets the text for the control.
/// </summary>
[Bindable(true),
Category("Appearance"),
DefaultValue(""),Description("Gets or sets the text for the control")]
public string Text
{
get
{
return text;
}

set
{
text = value;
}
}

/// <summary>
/// Gets or sets the text for the confirmation message.
/// </summary>
[Bindable(true),
Category("Appearance"),
DefaultValue("Are you sure you want to continue?"),Description("Gets or
sets the text for the confirmation message.")]
public string ConfirmationText
{
get
{
return confirmationText;
}

set
{
confirmationText = value;
}
}

/// <summary>
/// Gets or sets a value indicating whether client-side confirmation is
enabled.
/// </summary>
[Bindable(true),
Category("Appearance"),
DefaultValue(true),Description("Gets or sets a value indicating whether
client-side confirmation is enabled.")]
public bool EnableConfirmation
{
get
{
return enableConfirmation;
}

set
{
enableConfirmation = value;
}
}

/// <summary>
/// Gets or sets a value indicating what type of button to render.
/// </summary>
[Bindable(true),
Category("Appearance"),
Description("Gets or sets a value indicating what type of button to
render.")]
public RenderTypes RenderType
{
get
{
return renderType;
}

set
{
renderType = value;
}
}

/// <summary>
/// Gets or sets the url for the LinkButton RenderType.
/// </summary>
[Bindable(true),
Category("Navigation"),
DefaultValue(""),Description("Gets or sets the url for the LinkButton
RenderType.")]
public string NavigateUrl
{
get
{
return navigateUrl;
}

set
{
navigateUrl = value;
}
}

/// <summary>
/// Gets or sets the command name associated with the ConfirmButton
control.
/// </summary>
[Category("Behavior"),
Description("Gets or sets the command name associated with the
ConfirmButton control."),
DefaultValue("")]
public string CommandName
{
get
{
return commandName;
}

set
{
commandName = value;
}
}

/// <summary>
/// Gets or sets an optional argument passed to the Command event handler
along with the associated CommandName property.
/// </summary>
[Bindable(true),
Category("Behavior"),
Description("Gets or sets an optional argument passed to the Command event
handler along with the associated CommandName property."),
DefaultValue("")]
public string CommandArgument
{
get
{
return commandArgument;
}

set
{
commandArgument = value;
}
}

/// <summary>
/// Gets or sets a value indicating whether validation is performed when
the ConfirmButton control is clicked.
/// </summary>
[Bindable(false),
Category("Behavior"),
Description("Gets or sets a value indicating whether validation is
performed when the ConfirmButton control is clicked."),
DefaultValue(true)]
public bool CausesValidation
{
get
{
return causesValidation;
}

set
{
causesValidation = value;
}
}
#endregion

#region Events
/// <summary>
/// Occurs when ConfirmButton control is clicked.
/// </summary>
public event EventHandler Click;

/// <summary>
/// Occurs when the ConfirmButton control is clicked.
/// </summary>
public event CommandEventHandler Command
{
add
{
base.Events.AddHandler(ConfirmButton.EventCommand,value);
}
remove
{
base.Events.RemoveHandler(ConfirmButton.EventCommand,value);
}
}
#endregion

#region IPostBackEventHandler Members

/// <summary>
/// Notifies the server control that caused the postback that it should
handle an incoming post back event.
/// </summary>
/// <param name="eventArgument">The post-back argument.</param>
public void RaisePostBackEvent(string eventArgument)
{
this.OnClick(this, new System.EventArgs());
this.OnCommand(this,new
CommandEventArgs(this.CommandName,this.CommandArgument));
}

#endregion

}
}
 
T

Teemu Keiski

As it has child controls dealing with postback, your control is a composite
control and needs also implement INamingContainer interface so that the
postback data is routed correctly.

--
Teemu Keiski
ASP.NET MVP, AspInsider
Finland, EU
http://blogs.aspadvice.com/joteke

Demetri said:
I have created a web control that can be rendered as either a linkbutton or
a
button. It is a ConfirmButton control that allows a developer to force a
user
to confirm if they intended to click it such as when they do a delete.

Everything is great. By and large it will be used in my repeater controls
using the command event when the user clicks on it and so that event is
working great.

My issue is the Click event. When the control is either in a repeater or
by
itself on a page the click event does not fire. It never even gets raised
by
the ConfirmButton control, never mind the listener (ie. page container).

Does anyone have a clue as to why the RaisePostBackEvent never fires? That
is my ultimate question here.

HTML output:

<input type="submit" name="Confirmbutton1" value="Go" id="Confirmbutton1"
onclick="return __doConfirm();__doPostBack('MyPage:Confirmbutton1','')" />

Page using the control event wiring:

private void InitializeComponent()
{
this.Confirmbutton1.Click += new
System.EventHandler(this.Confirmbutton1_Click);
this.Load += new System.EventHandler(this.Page_Load);

}


private void Confirmbutton1_Click(object sender, System.EventArgs e)
{
Response.Write("Click event fired!");
}

Server Control Code:

using System;
using System.Text;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web.UI.HtmlControls;
using System.Collections;

namespace WS.Ops.Web.CustomControls
{
/// <summary>
/// Button that provides a client-side confirmation prompt. It can be
either a Button or LinkButton.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:ConfirmButton1 runat=server></{0}:ConfirmButton1>"),
Description("Button that provides a client-side confirmation prompt. It
can
be either a Button or LinkButton.")]
public class ConfirmButton : System.Web.UI.WebControls.WebControl,
IPostBackEventHandler
{
//the confirm button render types
public enum RenderTypes
{
LinkButton,
Button
};

#region Fields
private RenderTypes renderType = RenderTypes.LinkButton;
private WebControl controlToRender;
private const string CONFIRMSCRIPTKEY = "ConfirmScript";
private const string CONFIRMFUNCTIONNAME = "__doConfirm";
private string confirmationText = "Are you sure you want to continue?";
private string text = string.Empty;
private string navigateUrl = string.Empty;
private string commandArgument = string.Empty;
private string commandName = string.Empty;
private bool enableConfirmation = true;
private bool causesValidation = true;
private static readonly object EventCommand;
#endregion

#region Overrides
protected override void CreateChildControls()
{
base.CreateChildControls();

switch (RenderType)
{
default: // default is hyperlink
case RenderTypes.LinkButton:

LinkButton link = new LinkButton();
link.TabIndex = -1;
link.Text = this.Text;
link.Attributes.Add("href",Page.GetPostBackClientHyperlink(this,string.Empty));
link.Click += new EventHandler(this.OnClick);
link.Command += new CommandEventHandler(this.OnCommand);

if(EnableConfirmation)
link.Attributes.Add("onclick","return " + CONFIRMFUNCTIONNAME + "();");

controlToRender = link;

break;
case RenderTypes.Button:

Button button = new Button();
button.Text = this.Text;
button.Click += new EventHandler(this.OnClick);
button.Command += new CommandEventHandler(this.OnCommand);

if(EnableConfirmation)
button.Attributes.Add("onclick","return " + CONFIRMFUNCTIONNAME +
"();" + Page.GetPostBackEventReference(this,string.Empty));

controlToRender = button;

break;
}

//Copy control style attributes applied to this control
//to the control that will render
IEnumerator keys = this.Style.Keys.GetEnumerator();
while (keys.MoveNext())
{
string key = (string)keys.Current;
controlToRender.Style.Add(key, this.Style[key]);
}

//copy attributes applied to this control
//to the control that will render
IEnumerator attribKeys = this.Attributes.Keys.GetEnumerator();
while (attribKeys.MoveNext())
{
string key = (string)attribKeys.Current;
controlToRender.Attributes.Add(key, this.Attributes[key]);
}

if (this.CssClass != null && this.CssClass != string.Empty)
{
controlToRender.CssClass += " " + this.CssClass;
}

controlToRender.Enabled = this.Enabled;

controlToRender.ID = this.ID;
}

protected override void Render(HtmlTextWriter output)
{
EnsureChildControls(); //make sure child controls are created

//don't render this control, just the control chosen via
//the RenderType property
controlToRender.RenderControl(output);

}

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender (e);

//if enable confirmation then attach the
//confirm script to the page
if(EnableConfirmation)
{
RegisterConfirmationScript();
}
}

#endregion

#region Methods
private void RegisterConfirmationScript()
{
//only add the script to the page
//if it has not been added already
if(!Page.IsClientScriptBlockRegistered(CONFIRMSCRIPTKEY))
{
Page.RegisterClientScriptBlock(CONFIRMSCRIPTKEY,CreateJavaScriptFunction());
}
}

private string CreateJavaScriptFunction()
{
//build script string, the script is formatted for
//readability in view source
StringBuilder sb = new StringBuilder();
sb.Append("<script language=\"javascript\">" + Environment.NewLine);
sb.Append("\tfunction " + CONFIRMFUNCTIONNAME + "(){" +
Environment.NewLine);
sb.Append("\t\tvar agree = confirm(\"" + ConfirmationText + "\");" +
Environment.NewLine + Environment.NewLine);
sb.Append("\t\tif(agree){" + Environment.NewLine);
sb.Append("\t\t\treturn true;" + Environment.NewLine);
sb.Append("\t\t}" + Environment.NewLine + "else{" + Environment.NewLine);
sb.Append("\t\t\treturn false;" + Environment.NewLine);
sb.Append("\t\t}" + Environment.NewLine);
sb.Append("\t}" + Environment.NewLine);
sb.Append("</script>" + Environment.NewLine);

return sb.ToString();
}

protected virtual void OnClick(object sender, EventArgs e)
{
if(Click != null)
Click(this,e);
}

protected virtual void OnCommand(object sender,CommandEventArgs e)
{
CommandEventHandler handler =
(CommandEventHandler)base.Events[ConfirmButton.EventCommand];

if(handler != null)
handler(this,e);

base.RaiseBubbleEvent(this,e);
}
#endregion

#region Properties
/// <summary>
/// Gets or sets the text for the control.
/// </summary>
[Bindable(true),
Category("Appearance"),
DefaultValue(""),Description("Gets or sets the text for the control")]
public string Text
{
get
{
return text;
}

set
{
text = value;
}
}

/// <summary>
/// Gets or sets the text for the confirmation message.
/// </summary>
[Bindable(true),
Category("Appearance"),
DefaultValue("Are you sure you want to continue?"),Description("Gets or
sets the text for the confirmation message.")]
public string ConfirmationText
{
get
{
return confirmationText;
}

set
{
confirmationText = value;
}
}

/// <summary>
/// Gets or sets a value indicating whether client-side confirmation is
enabled.
/// </summary>
[Bindable(true),
Category("Appearance"),
DefaultValue(true),Description("Gets or sets a value indicating whether
client-side confirmation is enabled.")]
public bool EnableConfirmation
{
get
{
return enableConfirmation;
}

set
{
enableConfirmation = value;
}
}

/// <summary>
/// Gets or sets a value indicating what type of button to render.
/// </summary>
[Bindable(true),
Category("Appearance"),
Description("Gets or sets a value indicating what type of button to
render.")]
public RenderTypes RenderType
{
get
{
return renderType;
}

set
{
renderType = value;
}
}

/// <summary>
/// Gets or sets the url for the LinkButton RenderType.
/// </summary>
[Bindable(true),
Category("Navigation"),
DefaultValue(""),Description("Gets or sets the url for the LinkButton
RenderType.")]
public string NavigateUrl
{
get
{
return navigateUrl;
}

set
{
navigateUrl = value;
}
}

/// <summary>
/// Gets or sets the command name associated with the ConfirmButton
control.
/// </summary>
[Category("Behavior"),
Description("Gets or sets the command name associated with the
ConfirmButton control."),
DefaultValue("")]
public string CommandName
{
get
{
return commandName;
}

set
{
commandName = value;
}
}

/// <summary>
/// Gets or sets an optional argument passed to the Command event handler
along with the associated CommandName property.
/// </summary>
[Bindable(true),
Category("Behavior"),
Description("Gets or sets an optional argument passed to the Command event
handler along with the associated CommandName property."),
DefaultValue("")]
public string CommandArgument
{
get
{
return commandArgument;
}

set
{
commandArgument = value;
}
}

/// <summary>
/// Gets or sets a value indicating whether validation is performed when
the ConfirmButton control is clicked.
/// </summary>
[Bindable(false),
Category("Behavior"),
Description("Gets or sets a value indicating whether validation is
performed when the ConfirmButton control is clicked."),
DefaultValue(true)]
public bool CausesValidation
{
get
{
return causesValidation;
}

set
{
causesValidation = value;
}
}
#endregion

#region Events
/// <summary>
/// Occurs when ConfirmButton control is clicked.
/// </summary>
public event EventHandler Click;

/// <summary>
/// Occurs when the ConfirmButton control is clicked.
/// </summary>
public event CommandEventHandler Command
{
add
{
base.Events.AddHandler(ConfirmButton.EventCommand,value);
}
remove
{
base.Events.RemoveHandler(ConfirmButton.EventCommand,value);
}
}
#endregion

#region IPostBackEventHandler Members

/// <summary>
/// Notifies the server control that caused the postback that it should
handle an incoming post back event.
/// </summary>
/// <param name="eventArgument">The post-back argument.</param>
public void RaisePostBackEvent(string eventArgument)
{
this.OnClick(this, new System.EventArgs());
this.OnCommand(this,new
CommandEventArgs(this.CommandName,this.CommandArgument));
}

#endregion

}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top