locked
CompositeControl and order of LoadPostData RRS feed

  • Question

  • User-1643923816 posted

    Hello Guys,

    
    

    I have a kind of philosophical question about control creation.

    Let's imagine you have the following scenario :

    • A CompositeControl composed of a TextBox (let's name it SuperTextBox)
      • for a more realistic scenario, let's imagine this is a control including validation, AJAX stuff like AjaxControlToolkit controls, ...
    • Another CompositeControl composed of several "SuperTextBox" (let's name is MyContainer)

    So typically, here is how my SuperTextBox would look like :

       public class SuperTextBox : CompositeControl
       {
          private TextBox txt;
    
          public string Text 
          {
             get
             {
                this.EnsureChildControls();
                return this.txt.Text + "Super";
             }
             set
             {
                this.EnsureChildControls();
                this.txt.Text = value + "Super";
             }
          }
    
          protected override void CreateChildControls()
          {
             base.CreateChildControls();
             this.txt = new TextBox() { ID = "txt" };
             this.Controls.Add(this.txt);
          }
       }
    

    What do you think of this implementation ? Here, I do not want to implement IPostBackDataHandler (well at least I do not think it's necessary) as all my loading stuff is done by the internal TextBox. Do you agree with me so far ?

    So what I want to do now is to create the MyContainer control which will be the editor of a simple class. Let's take for example :

       [Serializable]
       public class MyObject
       {
          public string Name { get; set; }
          public string FirstName { get; set; }
       }

    So my feeling is that the MyContainer control should hold a property storing in the view state this object, and that this one should implement IPostBackDataHandler to fill it (if necessary).

    So I would suggest something like :

       public class MyContainer : CompositeControl, IPostBackDataHandler
       {
          private SuperTextBox txtName;
          private SuperTextBox txtFirstName;
    
          public MyObject Object
          {
             get { return (MyObject)ViewState["Object"]; }
             set { ViewState["Object"] = value; }
          }
    
          protected override void CreateChildControls()
          {
             base.CreateChildControls();
    
             this.txtName = new SuperTextBox() { ID = "txtName" };
             this.Controls.Add(this.txtName);
    
             this.txtFirstName = new SuperTextBox() { ID = "txtFirstName" };
             this.Controls.Add(this.txtFirstName);
          }
    
          protected override void OnPreRender(EventArgs e)
          {
             base.OnPreRender(e);
             this.Page.RegisterRequiresPostBack(this);
    
             this.txtName.Text = this.Object.Name;
             this.txtFirstName.Text = this.Object.FirstName;
          }
    
          #region IPostBackDataHandler Members
    
          bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
          {
             /* We want here to update the property with the newly posted value
              * Each control having its own mechanism for loading its postdata, we shall rely here
              * on the child control's properties
              */
             this.EnsureChildControls();
             this.Object.Name = this.txtName.Text;
             this.Object.FirstName = this.txtFirstName.Text;
             return true;
          }
    
          void IPostBackDataHandler.RaisePostDataChangedEvent()
          {
             //No Event to raise
          }
    
          #endregion
       }
    

    Here as I want to update my object, I implement the IPostBackDataHandler and I load my object with the new values. As my child control are already responsible of loading / validating / transforming their data, I do not want to load from postCollection, but really from my child controls.

    That's why I do "EnsureChildControls".

    However, we have no control - as far as I know - about the order into which the LoadPostData will be called. So there is a risk that when the MyContainer's LoadPostData method will be called, the TextBox's LoadPostData will not be called yet.

    As a result, I do not have the value.

     

    My question is "simple". What would you do ? Just some hints about my "specifications"

    • There are many validation / transformation / computation done in my SuperTextBox and so it should be responsible of loading its data from the post collection (do you agree ?)
    • I do not really want to do a DataboundControl (am I wrong ?) as they work as "fire and forget" and thus I should handle many events to get back the updated values
    • The solution I propose will increase the view state size but this is acceptable in my scenario where I will edit almost (99%) all the fields of MyObject via MyContainer.

    What do you think ?

    Tuesday, December 15, 2009 11:50 AM

Answers