Create Child Controls – Microsoft SharePoint 2010

Most web controls that have visual elements compose other controls into a greater whole. Every web control contains a Controls collection property that contains the controls of which it is composed.

The controls in the Controls collection are called child controls because a page is easily visualized as a tree of controls with the page as the root. Each node of the tree can have zero or more children.

Use the CreateChildControls to instantiate any child controls that your web control contains.

The first two things that happen when ASP.NET renders a page are the initialization and loading of each node of the tree. The next thing that happens is the loading of state into each node of the tree so that the tree correctly represents any user input.

State is stored in a hidden form field named __VIEWSTATE and its contents are used to rehydrate a page between postbacks. The loading of ViewState works only if ASP.NET is able to match each node in the current rendering with the previous version—the one with which the user interacted and submitted input.

Consider the following code snippet:

 

If you ran this code in ASP.NET 2.0, perhaps on a WSS 3.0 or MOSS 2007 site, the Web Part would render a button 50 pixels wide without error. However, the event handler will not fire when a user clicks the button because the MyWebPart class creates a new instance of the Button class each time it initializes. The myButton variable then references a new button.

When the ViewState loads to indicate that the user clicked a button, the new button has replaced the original button in the tree and the event doesn’t fire.

Here’s the correct way to write this code:

 

In this example, you are still creating a new instance each time—ASP.NET is stateless after all, but the timing of the operation allows the page rendering infrastructure to correctly associate the button with its state when it adds the button to the Controls collection.

When working with the page rendering life cycle, timing is everything. ASP.NET 3.5, the basis of SharePoint Foundation, is more forgiving in this regard. However, unless you know that your custom Web Part will never run in an older version of ASP.NET, it is a best practice to follow the simple rule—create your child controls inside CreateChildControls.
doug (frame 367 of smile clip)This post is an excerpt from the online courseware for our Microsoft SharePoint 2010 for Developers course written by expert Doug Ware.

Doug Ware is a SharePoint expert and an instructor for many of our SharePoint 2007 and SharePoint 2010 courses. A Microsoft MVP several times over, Doug is the leader of the Atlanta .NET User Group, one of the largest user groups in the Southeast U.S., and is a frequent speaker at code camps and other events. In addition to teaching and writing about SharePoint, Doug stays active as a consultant and has helped numerous organizations implement and customize SharePoint.

Be Sociable, Share!

2 thoughts on “Create Child Controls – Microsoft SharePoint 2010

  1. Ted Harwood

    We have a challenging problem that we need help with. We are implementing a custom grid control and using web part settings to enable/disable certain columns and buttons in the control. The issue is that when you click to apply the web part settings and enable a column for example, the grid does not change. Furthermore, when you refresh the page you get a Failed to Load Viewstate error.

    The grid is created as a custom Sharepoint Web Part and then adding the grid in CreateChildControls programmatically.

    However, we are having the following issue with applying web part settings that change the grid layout.

    If you go into the web part settings for the grid and change a setting that changes the grid layout (e.g. display edit button column) it causes a Failed to Load Viewstate error on refresh. If you close the browser and reopen it, it works fine (edit column is displayed). Since the control layout is saved in the viewstate, this error makes sense. However, the question we need help with is how to refresh the page programmatically when any web part setting is changed so that the changes to the grid display.

    The Web Part Editor fires an ApplyChanges event when you click Ok or Apply. This is what saves the changes. However, if we put a page redirect in this method to refresh the page, then the web part setting changes are not saved.

    What I need is a way first to detect whether any changes were made to the web part settings and then if changes were made, to refresh the page including the viewstate.

    If you look at the page lifecycle events below, this detection would have to happen somewhere after ApplyChanges and somewhere before the page is rendered. Maybe in SyncChanges?

    Steps to Simulate Error

    1. Create a simple grid in Sharepoint by inheriting from a grid component
    2. Create a web part setting that enables/disables one of the columns.
    3. Select to enable the column and then click Apply and then Ok

    Event Firing Sequence During Issue

    Checked Enable Edit Column and then clicked Apply in the Web Part Editor pane
    SPGridWebPart Constructor <- This causes a postback and it goes through the page lifecycle again
    Event OnInit
    Event CreateChildControls
    Event SPGridEditor:CreateChildControls
    Event Page Load
    Event grid_Load
    Event SPGridEditor:ApplyChanges <- The change to the edit column enabled setting is done here, but after the child controls are already created
    Event SPGridEditor:SyncChanges
    SPGridWebPart Constructor
    Event Page Load Complete
    Event OnPreRender
    Event grid_PreRender <- Page is rendered without the edit column even though box is checked to show the edit column
    Event SPGridEditor:RenderContents
    Clicked Ok in the web part editor pane
    SPGridWebPart Constructor
    Event OnInit
    Event CreateChildControls
    Failed to load viewstate error

    Code Snippets Showing the Web Part Setting for Enabling/Disabling Edit Column

    const Boolean c_boolEnableEditColumn = true;
    private Boolean _boolEnableEditColumn;
    [Category("Custom – Basics"),
    Personalizable(PersonalizationScope.Shared),
    WebBrowsable(true),
    DefaultValue(true),
    WebDisplayName("Enable Edit Column"),
    WebDescription("Show an edit column with an edit button for each item")]
    public Boolean boolEnableEditColumn
    {
    get { return _boolEnableEditColumn; }
    set { _boolEnableEditColumn = value; }
    }

    public SPGridWebPart()
    {
    boolEnableEditColumn = c_boolEnableEditColumn;
    }

    Reply
  2. Phil Wheat

    Ted – you’re running into one of the fun parts of SharePoint control management. You’ll need to pick up the current state in the PreRender event and update your controls to be current. Because the controls are added before the state itself has been loaded (due to the pipeline) the control state is either a page refresh behind (common) or out of synch with the data (which seems to be what you’re running into here.)

    There’s a good list of the event sequence at http://geekswithblogs.net/KunaalKapoor/archive/2012/07/18/sharepoint-webpart-life-cycle-events-and-event-sequence.aspx – I generally kept a copy of the Server Control Model page from http://www.amazon.com/Developing-Microsoft%C2%AE-Components-Developer-Reference/dp/0735615829 but the post is more detailed for this particular sequence.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *