ClickOnce Button Server Control Using Custom Web Server Control
Prevent double-click from users when server performs long process, and distribute as a Custom Web Server Control.
Introduction
Prevent double-click from most (not all) users when server performs a long process, and distribute as a Custom Web Server Control.
Background
Since the introduction of Custom Web Server Controls, developing a control on top of existing controls is faster than the times of .NET 1.1.
Using the Code
Prior to the birth of Custom Web Server controls, a few developers at CodeProject came out with the idea of how to do it the hard way. Now it's easy compared with old days. (Portions of my code were extracted from them as well; credits go to their hard work.)
To start with development, right-click the solution and add an "ASP.NET Server Control" project.
Rename your class, and make your custom control inherit from the existing ASP Button
as below:
// Your control will inherit from existing ASP Button
public class ClickOnceBtn : System.Web.UI.WebControls.Button
Give a meaningful name here; this will be the name that is displayed in the toolbox:
Override OnPreRender()
as below. What it does is:
- tag the
onClick
event as part of the attribute of our custom Web Server control - register the embedded js function that will be shown later
protected override void OnPreRender(EventArgs e)
{
this.UseSubmitBehavior = false;
this.Attributes.Add("onclick", "javascript:clickOnce(this)");
// Define the name and type of the client script on the page.
String csName = "ButtonClickScript";
Type cstype = this.GetType();
// Get a ClientScriptManager reference from the Page class.
ClientScriptManager cs = Page.ClientScript;
// Check to see if the client script is already registered.
if (!cs.IsClientScriptBlockRegistered(cstype, csName))
{
string[] names = this.GetType().Assembly.GetManifestResourceNames();
if (names.Length > 0)
{
// Write out the web resource url.
Assembly assembly = this.GetType().Assembly;
const string JAVASCRIPT_RESOURCE = ".disable.js";
Stream st = Assembly.GetExecutingAssembly().GetManifestResourceStream(
assembly.GetName().Name + JAVASCRIPT_RESOURCE);
StreamReader sr = new StreamReader(st);
this.Page.ClientScript.RegisterClientScriptBlock(
this.GetType(), csName, sr.ReadToEnd(), true);
}
}
base.OnPreRender(e);
}
which in-turn calls this JavaScript:
function clickOnce(btn, msg) {
// Test if we are doing a validation
if (typeof (Page_ClientValidate) == 'function') {
// if we are doing a validation, return if it's false
if (Page_ClientValidate() == false) { return false; }
}
// Ensure that the button is not of type "submit"
if (btn.getAttribute('type') == 'button') {
// The msg attibute is absolutely optional
// msg will be the text of the button while it's disabled
if (!msg || (msg = 'undefined')) { msg = 'Loading...'; }
btn.value = msg;
btn.disabled = true;
}
return true;
}
Remember to set the .js file as an embedded resource. We do not want the host file carried to many individual files, just one DLL.
Yes, that's it. Easy, huh?
Now we create a test harness web-page and add our Custom Web Server Control to the host file.
In case you want to do some client-side verification on the host page, before calling the Custom Web Server Control, the script will be something similar to this:
where confirmProceed()
is:
function confirmProceed() {
var r = confirm("Confirm to proceed?");
if (r == false) {
return false;
}
return true;
}
Points of Interest
If your ASP page contains some validators, it might affect page validation; try to play around with this function:
// Test if we are doing a validation
if (typeof (Page_ClientValidate) == 'function') {
// if we are doing a validation, return if it's false
if (Page_ClientValidate() == false) { return false; }
}
History
Coming soon, if any.