“How do I make a property on my control be changable from javascript?“
I've seen this question asked, in various forms, quite a few times, and now that an irc buddy got stumped by it, I decided to blog my perspective on the best way to handle it.
So here is a big fat commented but untested code block:
using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
/// <summary>
/// This control has a public serverside property <see cref="MyProperty"/>
/// which is accessible on the client side via a hidden input element
/// </summary>
public class TestControl : WebControl, INamingContainer {
/// <summary>
/// This is the public property that I wish to expose to the clientside as well.
/// </summary>
/// <remarks>
/// Most public server control properties will use ViewState as their backing store.
/// ViewState, however, is not accessible view clientscript.
/// So instead, we'll use a hidden input child control to hold the value.
/// </remarks>
public String MyProperty {
get {
this.EnsureChildControls(); // This call makes sure that MyPropertyHolder is initialized
return MyPropertyHolder.Value;
}
set {
this.EnsureChildControls(); // This call makes sure that MyPropertyHolder is initialized
this.MyPropertyHolder.Value = Value;
}
}
/// <summary>
/// This is the hidden input control used to hold the value for MyProperty between postbacks.
/// </summary>
private HtmlInputHidden MyPropertyHolder;
/// <summary>
/// This method is called by EnsureChildControls when ChildControlsCreated is false.
/// You can think of it as the "initializer" for your composite control.
/// </summary>
protected override void CreateChildControls() {
this.Controls.Clear();
// This is where we actually instantiate the hidden input and add it to the composite control.
// If we needed to set some default value, we'd do it here.
MyPropertyHolder = new HtmlInputHidden();
MyPropertyHolder.ID = "MyProperty";
this.Controls.Add(MyPropertyHolder);
// Obviously, this control doesn't do anything interesting without other content besides the hidden input.
// This is where we would add other controls as children in order for our control to do what we want it to.
}
#region Composite Control Pattern
// This is a common pattern for implementing a composite control.
// These two methods, combined with the INamingContainer interface
// create a composite control
/// <summary>
/// This override makes sure that if we or somebody else tries to access our child controls,
/// that they will have been created in time.
/// </summary>
public override ControlCollection Controls {
get {
this.EnsureChildControls();
return base.Controls;
}
}
/// <summary>
/// I also override render here to make absolutely sure that at any point during runtime or
/// design time that the control is told to render itself, that it is ready to do so.
/// </summary>
protected override void Render( System.Web.UI.HtmlTextWriter writer ) {
this.EnsureChildControls();
base.Render(writer);
}
#endregion
}
Any Questions? :)