Composite Control Design Time Behavior

Last post 12-19-2006 1:29 PM by jorgegrajales090. 7 replies.

Sort Posts:

  • Composite Control Design Time Behavior

    01-07-2005, 10:10 AM
    • Member
      30 point Member
    • alexrosen
    • Member since 09-30-2002, 4:56 PM
    • Posts 6
    I am running into trouble using controls that inherit from the CompositeControl class at design time. Here is a simple example control:

    namespace TestControls
    {
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:TestControl runat=server></{0}:TestControl>")]
    public class TestControl : CompositeControl
    {
    private TextBox createdControl;

    [Browsable(true), Category("Misc")]
    public String Text
    {
    get
    {
    EnsureChildControls();
    return createdControl.Text;
    }
    set
    {
    EnsureChildControls();
    createdControl.Text = value;
    }
    }

    protected override void CreateChildControls()
    {
    createdControl = new TextBox();
    Controls.Add(createdControl);
    }
    }
    }

    The control runs fine. However, at design time it does not show the value I set for its Text property whether I set it in the aspx page's source view or design view. In design view if I type a value for Text into the property grid it is immediately erased although whatever I type does show up in source view and therefore at run time.

    I have run the debugger on an instance of VS 2005 to see what is going on at design time. What I find is that CreateChildControls executes twice at design time. The first time happens as a result of the ControlBuilder initializing the properties which leads to a call to EnsureChildControls and then the overridden CreateChildControls. The second time is when the CompositeControlDesigner's GetDesignTimeHTML method calls its own CreateChildControls which calls RecreateChildControls (from ICompositeControlDesignerAccessor). That method calls EnsureChildControls but apparently with the flag that indicates whether the controls have been created reset so the controls are created again. However, their properties are not set after this second creation.

    I have been reading the Kothari/Datye book and implemented a rudimentary designer that overrode the GetDesignTimeHTML method. Although I haven't traced that version, it seems that the call to the base class's method causes the same issue. How can I avoid this double creation during design time or, if it is necessary, get the properties that were set during the first creation copied onto the controls that are created during the second creation? Of course I would hope there is a generic solution that allows me to use the same designer on several different simple composite controls.

    Thanks,
    - Alex Rosen
  • Re: Composite Control Design Time Behavior

    01-07-2005, 10:18 AM
    • All-Star
      29,644 point All-Star
    • Fredrik N
    • Member since 06-22-2002, 5:03 AM
    • Sweden
    • Posts 5,334
    • TrustedFriends-MVPs
    Remove the EnsureChildControls() form the Text property, set the TextBox control within the constructor. The following example works fine:


    namespace TestControls
    {
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:TestControl runat=server></{0}:TestControl>")]
    public class TestControl : CompositeControl
    {
    private TextBox createdControl;

    public TestControl()
    {
    createdControl = new TextBox();
    }

    [Browsable(true), Category("Misc")]
    public String Text
    {
    get
    {
    return createdControl.Text;
    }
    set
    {
    createdControl.Text = value;
    }
    }

    protected override void CreateChildControls()
    {
    Controls.Add(createdControl);
    }
    }
    }
    /Fredrik Normén - fredrikn @ twitter

    ASPInsider

    Microsoft MVP, MCSD, MCAD, MCT

    ASPInsiders
    My Blog
  • Re: Composite Control Design Time Behavior

    01-07-2005, 10:32 AM
    • Member
      30 point Member
    • alexrosen
    • Member since 09-30-2002, 4:56 PM
    • Posts 6
    Frederik,

    Thanks so much for that simple and elegant solution. I knew there had to be an easy way but everything I was reading was steering me away from what should have been more obvious.

    Thanks!

    - Alex Rosen
  • Re: Composite Control Design Time Behavior

    02-15-2005, 8:27 PM
    • Participant
      1,910 point Participant
    • SimonCal
    • Member since 06-10-2002, 8:43 PM
    • Posts 381
    • AspNetTeam
      Moderator
    The current CompositeControl base class exposes an accessor that is used to recreate the child controls in the designer scenario. This performs a forceable recreate of the collection. However, when this occurs, the issue is that the proeprty sets that you have delegated to the child controls are lost immediately.

    The design pattern for composite control therefore was such that it assumes a parent needs the ability at any time to recreatechildcontrols and therefore needs to hold onto state itself rather than delegating to the children. This will be true, if for example you create a composite control tthat exposes templates too.

    Hope this helps.
    Simon
    This posting is provided "AS IS" with no warranties, and confers no rights.
  • Re: Composite Control Design Time Behavior

    09-13-2006, 1:10 PM
    • Member
      60 point Member
    • rrahlf
    • Member since 09-15-2004, 3:51 PM
    • Wisconsin
    • Posts 14

    I realize this post is over a year behind the conversation, but I'll give it a shot anyway.

    I've also recently run into this issue, and found the same solution thanks in part to an article by Dino Esposito.  However, in all the examples I've seen on the web and in Dino's source code, I notice that the view state of the child controls is never disabled.  Wouldn't this create dupicate entries for properties in the viewstate? 

    It seems to me that directly exposing the properties of child controls - rather than maintaining state in the parent control - is more in-line with the idea of why we should create a composite control in the first place; leverage the power of the child controls and let them handle their own state, postback, rendering ect.  It seems that the ICompositeControlDesignerAccessor and CompositeControlDesigner are cripling this methodology for run-time by requiring the CompositeControl to handle CreateChildControls at any time during the design-time.  I do see the requirement for rebuilding the control tree at design time for a control which changes it's control tree dramaticly based on a property or template.  However, in simple cases such as Alex Rosen's above, shouldn't the the Designer request that the control be re-rendered, not rebuilt?

    That being the case, does anyone find fault with leaving the control as Alex wrote it in his original post, thus eliminating duplicates in the view state at run-time, but overriding the ICompositeControlDesignerAccessor.RebuildControls() method to maintain the control's viewstate across rebuilds?

        Protected Overrides Sub RecreateChildControls()
            Dim c As Object = Me.SaveControlState()
            Dim v As Object = Me.SaveViewState()
    
            MyBase.RecreateChildControls()
    
            Me.LoadControlState(c)
            Me.LoadViewState(v)
        End Sub
     
    Ryan Rahlf
  • Re: Composite Control Design Time Behavior

    09-13-2006, 2:02 PM
    • Member
      60 point Member
    • rrahlf
    • Member since 09-15-2004, 3:51 PM
    • Wisconsin
    • Posts 14

    Just after writing the post above, I came across a blog post very much in the same discussion by Dave Reed [Infinity88].

    I'm going to call "store the property value to the viewstate and set the child control property in CreateChildControls" method the "ViewState Method".  The "expose child control properties directly and use EnsureChildControls in Init or in each property accessor" method the "Expose Method".

    Dave seems to be thinking along the same lines as I am - that the ViewState Method of exposing child control properties is inefficient, causing duplicates - but Dave brings up another good point: the ViewState Method fails once CreateChildControls is called at run-time.  Read Dave's blog for details. 

    Comments on Dave's blog by Stefaan Rillaert and Simone Busoli also hit upon the same design-time issue as I had with the Expose Method, it doesn't work at design-time.  Both methods are trying to overcome the shortcomings of the other; the ViewState Method works better at design-time, the Expose Method works better at run-time.  So what's the "holy-grail" solution?

    Busoli mentions in Reed's blog that using the Expose Method and overriding RecreateChildControls as

    protected override void RecreateChildControls()
    {
    EnsureChildControls();
    }

     solved the Expose Method's state-loss-at-design-time issue in his case, but that method isn't going to work for a control like the new .NET 2.0 LoginControl which renders different templates based on a property value.  In that case, simply calling EnsureChildControls wouldn't clear the control tree and recreate the alternate template as desired.  My implementation of RecreateChildControls I listed in my last post will aslo fail in this case, since the view state cannot be restored if the owning controls are missing from the control tree. 

    It feels like the CompositeControlDesigner's method of calling RecreateChildControls whenever any property is changed in design-mode is a hammer too large for the nail.  I can't think of a catch-all solution, but perhaps there isn't one.  Some design-time property changes are going to require the control tree to be rebuilt, some will only require a redraw.  The answer may be to create a PropertyAttribute that indicates whether a property change at design time should generate a rebuild or a redraw.  The default action would be a redraw, but special properties like the one that changes the template for the LoginControl would be marked as "cause design-time rebuild". 

    Are there any resources that offer a good examination of design-time attribute classes?  We've probably all seen Description and Category, but I've just recently run into RefreshProperties and NotifyParentPropertyAttribute which are still a bit of a mystery.  There may already be a property attribute that accomplishes what I'm suggesting, but I'm not sure where to look.

    Ryan Rahlf
  • Re: Composite Control Design Time Behavior

    09-13-2006, 4:42 PM
    • Member
      60 point Member
    • rrahlf
    • Member since 09-15-2004, 3:51 PM
    • Wisconsin
    • Posts 14

    Here's a list of common design-time attributes:

    http://msdn2.microsoft.com/en-us/library/a19191fh.aspx

    http://msdn2.microsoft.com/en-us/library/tk67c2t8.aspx

    and the whole namespace:

    http://msdn2.microsoft.com/en-us/library/system.componentmodel.aspx

    RefreshProperties is particularly interesting in relation to CompositeControl, but I don't think it's the entire solution.

    Ryan Rahlf
  • Re: Composite Control Design Time Behavior

    12-19-2006, 1:29 PM

    I have a problem with the composite control design time behavior...

    I have a class that inherits from compositeControl and in the CreateChildControls method I add a label with a custom text value. But I want set the label style from a skin file. In the browser all works fine, but in design time not appears the style that I set in the skin file. And @Page Theme="" and StyleSheetTheme="" is not the solution, because with the other controls like the label, the theme applies very well.

    Some of you has the same problem? How I can solution that.

     Regards..
     

     


     

     

Page 1 of 1 (8 items)
Microsoft Communities