Client side properties in ASP.net server controls mini-pattern
I've been writing a couple of asp.net server controls recently, and those of you who have written them will know that it's a painful process until you get to know the life cycle of the controls. One of the controls I wrote required some properties to be available as a server-side property and the same value available to be settable from the client-side javascript, so I've put together this mini-pattern on how to do it. There's no ajax involved here, just a normal postback without having to write too much plumbing.
Starting with a control that inherits from System.Web.UI.WebControls.WebControl I also implement INamingContainer so that the hidden field I am going to use will have a unique id.
public class MyWebControl : WebControl, INamingContainer
Next I add the server side property with viewstate.
public string MyClientVisibleValue
{
get { object obj = ViewState["myvalue"];
return (obj == null) ? string.Empty : (string)obj;}
set { ViewState["myvalue"] = value;}
}
Now this value does get sent to the client, but it's buried in the viewstate hidden field so I add my own hidden field to send the value to the client.
private HiddenField _myValueHiddenField;
protected override void CreateChildControls()
{
_myValueHiddenField = new HiddenField();
this.Controls.Add(_myValueHiddenField);
base.CreateChildControls();
}
I'm not going to set the value of the hidden field in CreateChildControls because we want to send the server side value back to the client after any server side processing has happened. The following two functions take care of sending the value to the client and getting it back.
protected override void OnLoad(EventArgs e)
{
if (Page.IsPostBack)
{
EnsureChildControls();
this.MyClientVisibleValue = _myValueHiddenField.Value;
}
base.OnLoad(e);
}
protected override void OnPreRender(EventArgs e)
{
_myValueHiddenField.Value = this.MyClientVisibleValue;
RegisterScripts();
base.OnPreRender(e);
}
To access the value on the client the ClientID of the hidden field is need so we substitute it into our client side script.
private string StartupScriptID
{
get{return "startup_" + this.ClientID;}
}
protected virtual void RegisterScripts()
{
if (!Page.ClientScript.IsStartupScriptRegistered(GetType(), this.StartupScriptID))
{
Page.ClientScript.RegisterStartupScript(GetType(), this.StartupScriptID,
String.Format("alert(document.getElementById(\"{0}\").value);document.getElementById(\"{0}\").value = \"some value\"",
this._myValueHiddenField.ClientID), true);
}
}
In this case I have a simple script that displays the current value in a dialog and then assigns "some value" to the property. That value will then be assigned to the server-side property on the next postback. Add the control to an aspx page using the code below
<%@ Register TagPrefix="demo" Namespace="MyNamespace" %>
Declare the control within the <form> tags
<demo:MyWebControl ID="foo" runat="server" MyClientVisibleValue="start value" />
Full code listing is attached to this post.