Composite control with dynamic controls depending on a property value

Discussion in 'ASP .Net Building Controls' started by Matt Sollars, Jul 27, 2004.

  1. Matt Sollars

    Matt Sollars Guest

    Hi, all. I am really stuck here. I've written a few composite controls
    before and fully understand the "typical" scenarios. However, this one is
    far different. I understand that CreateChildControls must create the
    controls in exactly the same way as it did before a post-back in order for
    everything to "link" back up properly.

    However, I have a composite control that creates a single label and a single
    custom control. The catch is, the single custom control is determined by a
    property value. This makes things very complicated, it seems. I'd like to
    create the children when the property is set. I'd also like to get the
    property's value BEFORE the children are re-created upon post-back. That
    way, I know which custom control to create when re-creating.

    Any ideas? I'm afraid I've put myself in a bit of a bind by thinking I could
    pull this off.

    Thank you in advance,

    Matt
     
    Matt Sollars, Jul 27, 2004
    #1
    1. Advertising

  2. Hi Matt,

    As for the composite control with dynamic created control(depending on a
    certain property value) issue you mentioned, here are some of my opinions:

    1. Since the dynamic's creation depend on a property of the composition
    control, then where to maintain this property should be our first problem.
    The creating of sub control hierarchy (when postback) is before loading
    viewstate , so using ViewState to store the property may cause abit problem
    in the page's sequential post back.
    Alternatively, we can use a custom <intput type="hidden" > element or even
    the SessionState to maintain this.But still make the problem too complex.

    2. Then, if we still want to use ViewState to maintian the property, we
    should do some particular changes in our CreateChildControl function.
    There, we create the whole control hierarchy of the composite control, and
    I think we need to make the "Dynamic control" be created everytime in
    CreateChildControl, then, when we set the certain property of the server
    controls, we change the "Dynamic Control"'s visible feature according to
    the certain property. Thus, we can avoid struggling with "where to create
    the control?" , " where to store the proerty value so that it can be always
    accessable when control is being recreated"
    How do you think so?
    If have any other ideas , please feel free to post here. Thanks.

    Regards,

    Steven Cheng
    Microsoft Online Support

    Get Secure! www.microsoft.com/security
    (This posting is provided "AS IS", with no warranties, and confers no
    rights.)

    Get Preview at ASP.NET whidbey
    http://msdn.microsoft.com/asp.net/whidbey/default.aspx
     
    Steven Cheng[MSFT], Jul 28, 2004
    #2
    1. Advertising

  3. Matt Sollars

    Matt Sollars Guest

    Re: Composite control with dynamic controls depending on a propertyvalue

    Steven,

    You make some very good points. I appreciate your input. The fact is, I
    considered your second option and decided against it only to briefly
    ponder your first option (a hidden input). The second option seems the
    best to get this to work, but I was concerned with memory on the server,
    at first. Maybe it's a moot point considering.

    This is a survey tool for the government. I reduced a 50 table database
    to 7 tables, by making things dynamic. The property I mentioned on this
    composite control is an enumeration representing an answer type:
    SingleLine, MultiLine, DropDownList, RadioButtonList, etc. The added
    catch is, there are other properties that need to reference this
    dynamically created control. Such as, the answer already given, choices
    for multiple choice questions, and a few other layout properties.

    Normally, this would really complicate things, but each of these dynamic
    controls descends from a base. So, it's conceivable that I could follow
    your suggested #2 option. However, I think I would need to override the
    LoadViewState method in order to ensure that the AnswerType property is
    read first. That way, the proper control is the only one visible and set
    to an internal variable of the base type. Then, after each of the other
    properties are loaded from view state, the needed properties of the
    visible control can be set.

    I was wondering though; since this control is in a repeater, would
    several instances of it (with an instance of each child control;
    although invisible) take up too much memory on the server? I guess I'll
    have to find out.

    Thanks again for the help, Steven.

    Regards,
    Matt
     
    Matt Sollars, Jul 28, 2004
    #3
  4. Matt Sollars

    Matt Sollars Guest

    Steven:

    I have a possible solution but I am missing something. I've been messing
    with this for a couple of hours today after I replied to you this
    morning.

    I have changed all the composite's properties to store their values in
    private fields. The AnswerType property defaults to a value of NotSet.
    My CreateChildControls() method only creates the children if AnswerType
    is NOT NotSet (so, something has to be set before the children are
    created). Once the child control is created, an event handler is added
    for the appropriate Changed event.

    I have overridden SaveViewState and LoadViewState. SaveViewState stores
    AnswerType first, then appends base.SaveViewState() before returning.
    LoadViewState reads AnswerType first, then it sets ChildControlsCreated
    to false and calls EnsureChildControls() to create the children now that
    there is a valid value for AnswerType. Then, it calls base.LoadViewState
    to finish up.

    Finally, I have overridden the OnPreRender() method. Here, I am setting
    all of the child control's properties from the private variables.

    This seems to be working fantastically. Only the needed control is
    created on post-backs. However, I still can't get events to fire for the
    child control. I'm creating the exact same child control in the exact
    same order after post-back.

    Am I missing something in the timing?

    Thanks a bunch,
    Matt

    *** Sent via Developersdex http://www.developersdex.com ***
    Don't just participate in USENET...get rewarded for it!
     
    Matt Sollars, Jul 28, 2004
    #4
  5. Hi Matt,

    Thanks for your response. Since you mentioned that you set the private
    field default to NotSEt, when do you set the intial value or if you want to
    do change , when will you set new value to it? In page's Init Or post back
    event and does any change to the AnswerType filed will make the
    createChildControl be recalled( recreate the control)?
    In addition, I think it'll be more helpful if you can provide a simplified
    demo which can demostrate your new solution so that I can do some tests on
    my side.

    Thanks.

    Regards,

    Steven Cheng
    Microsoft Online Support

    Get Secure! www.microsoft.com/security
    (This posting is provided "AS IS", with no warranties, and confers no
    rights.)
     
    Steven Cheng[MSFT], Jul 29, 2004
    #5
  6. Matt Sollars

    Matt Sollars Guest

    Hello again, Steven.

    After more testing yesterday, I finally got things working. I'll admit,
    it took quite a bit of studying the Page's request processing.

    The solution, ultimately, was to store all property values in private
    fields. The set of each property only sets the fields; it does not call
    EnsureChildControls, since the AnswerType property absolutely must be
    set before others can "carry through" to the dynamic child control. In
    case, it is called, CreateChildControls checks that AnswerType != NotSet
    before creating the child.

    SaveViewState stores AnswerType and the AnswerValue, then calls the base
    implementation. LoadViewState loads AnswerType and the original
    AnswerValue, then calls EnsureChildControls which creates the
    appropriate child control. Then, it calls the base implementation.
    OnPreRender sets the child control's properties from the private fields
    since everything should be created and set at this point. Finally,
    OnLoad reverses this if IsPostBack is true, by setting the private
    fields to the values of the child control's properties to restore the
    state of the composite control and indicate any changes by the user.

    The original design was relying on the appropriate Change event of the
    child to indicate that a change was made. Since I couldn't get the
    events to fire, I'm checking the original AnswerValue against the child
    control's value after post-back for any change.

    I would really like to create a scaled down demo for testing and to see
    if I've created a "hack" instead of a proper solution. However, I'm
    already a bit behind on 2 projects, so it may be a week or so.

    Thanks for all your help and I'll get back to you soon.

    Regards,
    Matt

    *** Sent via Developersdex http://www.developersdex.com ***
    Don't just participate in USENET...get rewarded for it!
     
    Matt Sollars, Jul 29, 2004
    #6
  7. Hi Matt,

    Thanks for your followup. Well, I'm also doing some test on my side. And
    I've made a simple demo and which use public property to wrapper a private
    field and when the property is reset, if the value is changed, I'll recall
    the CreateChildControl to reconstruct the composite control. And I also
    override the Load/SaveViewState method to handle the maintainance of the
    controltype field. I've attached my demo class and test page in this
    message, you can use OE client to view this messsage and get the
    attachment. (I'll also paste the control's code in the bottom of this
    message)Also, I find that you haven't register a email address for your
    managed account, I recommend that you register one so that we can nofify
    you when there is any update in your issues.

    Anyway, if you have any updates , please feel free to let me know.

    Thanks.

    Regards,

    Steven Cheng
    Microsoft Online Support

    Get Secure! www.microsoft.com/security
    (This posting is provided "AS IS", with no warranties, and confers no
    rights.)

    =====================================================
    [DefaultProperty("Text"),
    ToolboxData("<{0}:SimpleCC runat=server></{0}:SimpleCC>")]
    public class SimpleCC : System.Web.UI.WebControls.WebControl
    {
    private string text;
    private int _type = 0;

    public int Type
    {
    get
    {
    return _type;
    }
    set
    {
    if(value != _type)
    {
    _type = value;
    this.ChildControlsCreated = false;
    this.EnsureChildControls();
    }
    }
    }

    [Bindable(true),
    Category("Appearance"),
    DefaultValue("")]
    public string Text
    {
    get
    {
    return text;
    }

    set
    {
    text = value;
    }
    }

    /// <summary>
    /// Render this control to the output parameter specified.
    /// </summary>
    /// <param name="output"> The HTML writer to write out to </param>
    // protected override void Render(HtmlTextWriter output)
    // {
    // output.Write(Text);
    // }
    public SimpleCC()
    {

    }

    public SimpleCC(int type)
    {
    if(type>= 0 && type<3)
    {
    this._type = type;
    }
    }

    protected override void LoadViewState(object savedState)
    {
    Triplet triplet = savedState as Triplet;
    _type = (int)triplet.First;

    this.ChildControlsCreated = false;
    this.EnsureChildControls();

    base.LoadViewState (triplet.Second);
    }

    protected override object SaveViewState()
    {
    Triplet triplet = new Triplet(_type,base.SaveViewState());

    return triplet;
    }

    protected override void CreateChildControls()
    {
    //base.CreateChildControls ();
    Controls.Clear();
    switch(_type)
    {
    case 0:
    Label lbl = new Label();
    lbl.ID = "lblDynamic";
    lbl.Text = "Dynamic Label";
    Controls.Add(lbl);

    break;
    case 1:
    TextBox txt = new TextBox();
    txt.ID = "txtDynamic";
    txt.AutoPostBack = true;
    txt.TextChanged +=new EventHandler(txt_TextChanged);
    Controls.Add(txt);
    break;
    case 2:

    Button btn = new Button();
    btn.ID = "btnDynamic";
    btn.Text = "Dynamic Button";
    btn.Click +=new EventHandler(btn_Click);
    Controls.Add(btn);
    break;


    }
    }


    protected void txt_TextChanged(object source, EventArgs argument)
    {
    TextBox txt = (TextBox)source;
    Page.Response.Write("<br>" + txt.ID + " posted back");
    }

    protected void btn_Click(object source, EventArgs argument)
    {
    Button btn = (Button)source;
    Page.Response.Write("<br>" + btn.ID + " posted back");
    }


    }
    ==================================================
     
    Steven Cheng[MSFT], Jul 30, 2004
    #7
  8. Matt Sollars

    Matt Sollars Guest

    Re: Composite control with dynamic controls depending on a propertyvalue

    Thanks for the code, Steven.

    There must be something in all of my comvoluted code that was preventing
    the child event from firing. I'll certainly revisit the issue in short
    time. Again, thanks for the test files. They work great and we've found
    a way to get this thing to work without creating all the possible
    controls or using a hidden. It's a good thing.

    Regards,

    Matt
     
    Matt Sollars, Jul 30, 2004
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sleigh
    Replies:
    1
    Views:
    2,707
    sleigh
    Feb 12, 2004
  2. Harry
    Replies:
    2
    Views:
    665
    Harry
    Apr 16, 2004
  3. Chad
    Replies:
    0
    Views:
    237
  4. Bryan
    Replies:
    2
    Views:
    225
    Bryan
    Jun 14, 2006
  5. Mike

    Composite vs non composite Controls

    Mike, Mar 10, 2005, in forum: ASP .Net Web Controls
    Replies:
    4
    Views:
    272
    Sundararajan
    Mar 11, 2005
Loading...

Share This Page