in

ASP.NET Weblogs

Andy Smith's Blog

Page.RegisterStartupScript('Andy', 'MetaBuilders_WebControls_GainKnowledge();');

making control properties accessible to both server and clientside code

“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? :)

Comments

No Comments

Leave a Comment

(required)  
(optional)
(required)  
Add