SharePoint Internals – Hristo Pavlov’s Blog

10 December, 2008

Deploying WebParts with a DelegateControl

Brian Farnhill talks about an interesting approach of deploying zoneless web parts by using a Delegate Control in your master page or page layout. See his blog post here:  http://pointstoshare.spaces.live.com/Blog/cns!AEC42F315B4528B0!3247.entry

The idea is that you add a DelegateControl in your master page or page layout and configure it’s ControlId to a unique id that you are going to define in a separate feature by using a Control element. This way you can replace the control/web part without the need of changing the master page but only by updating your feature. Even more you can activate different controls in different sites by activating different features in those sites, which define different controls with the same Id that matches the ControlId configured in the DelegateControl.

When SharePoint is searching for the control specified in the DelegateControl it can also search only features of a specific scope i.e. Web, Site, etc. This can be configured from the Scope attribute of the DelegateControl. Also you can configure only one control to be rendered or all controls with this id to be rendered with the AllowMultipleControls attribute. If no matching Control element could be found, then no control is rendered i.e. if you want to remove the web part, just deactivate the feature. Additionally the DelegateControl allows a PrefixHtml and SuffixHtml to be defined.

You will probably want to use this approach when you need for different sites to show different web parts on the same location of the page. You do this by using a single page layout (or master page) with a single DelegateControl and then activating different features on those sites which will activate the different web parts to be rendered. Very nice indeed!

Delegate controls are used for defining the search controls in SharePoint. The web controls that are going to be hosted must be registered as safe. You can also host ASCX web user controls the same way.

Advertisements

23 May, 2008

Why Should I Specify an ID for Dynamically Created HtmlControls in my WebParts

Filed under: ASP.NET, SharePoint — Tags: , , , , , — hristopavlov @ 2:24 am

What Is Happening:

Following the best practices for implementing WebParts we often create our controls dynamically in the CreateChildControls() method. However if your web part uses a ToolPart your server event handlers (such as OnClick handlers) may not be called.

When It Is Happening:

This problem happens with your dynamically created System.Web.UI.HtmlControls if you don’t specify the ID of the controls.

HtmlButton button = new HtmlButton();

tableCell.Controls.Add(button);

button.InnerText = “Create”;

button.ServerClick += new EventHandler(ButtonCreate_click);

The problem is only occurring if your web part implements a ToolPart.

Why It Is Happening:

What is happening is that, in the case there is a ToolPart involved, the CreateChildControls() comes before OnLoad(). So when we recreate our controls without giving them names they won’t have any name assigned until a later stage. At this later stage they will be given system generated names such as “ctl01“. However this later stage happens after the post back events (such as OnClick) are raised. When ASP.NET tries to call the event handlers it is not able to locate your controls because they don’t have an ID yet and no match can be found to the control that has generated the post back and is specified in the __EVENTTARGET  hidden field: 

private void RaisePostBackEvent(NameValueCollection postData)

{

    if (this._registeredControlThatRequireRaiseEvent != null)

    {

        this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent, null);

    }

    else

    {

        stringstr = postData[“__EVENTTARGET”];

        bool flag = !string.IsNullOrEmpty(str);

 

        if (flag || (this.AutoPostBackControl != null))

        {

            Control control = null;

            if (flag)

            {

                control = this.FindControl(str);

            }

 

            if ((control != null) && (control.PostBackEventHandler != null))

            {

                stringeventArgument = postData[“__EVENTARGUMENT”];

                this.RaisePostBackEvent(control.PostBackEventHandler, eventArgument);

            }

        }

        else

        {

            this.Validate();

        }

    }

}

The problem with the different order of events was reported as well for example in the following post: http://www.schaeflein.net/blog/2004/03/29/OrderOfEventsInWebPart.aspx. I did a further experiment and found that this is exactly the reason for the problem. For example when I called manually base.Load() at the beginning of the CreateChildControls() everything was working fine even without explicitly giving a name to my controls.

How To Solve It:

Remember to always give names (ID) to your dynamically generated controls. This not only resolves this particular issue but also guarantees that system generated names will not cause same controls to have different IDs between different responses from the same page, which you don’t really want.

HtmlButton button = new HtmlButton();

tableCell.Controls.Add(button);

button.InnerText = “Create”;

button.ID = “btnCreate”;

button.ServerClick += new EventHandler(ButtonCreate_click);

 

Blog at WordPress.com.