Using a Control Adapter for Branding Part 2

In part 1 I described why a developer might choose to use a control adapter for branding out of the box SharePoint web parts.  In part 2 I will explain how to create a control adapter and how you can deploy it to work with SharePoint.   In part 3 I will show an easier way for integrating control adapters into your SharePoint environment.

A control adapter allows a developers to change the default rendering behavior of any control.  In the case of SharePoint we can use the control adapter to modify how all or specific out of the box web parts are rendered.  This allows us to easily apply custom classes, styles and tags to the rendered output so we can control the branding of those web parts.

The branding that I wanted to accomplish was to have all 4 corners of the web parts rounded and put styles in place to complete the intended effect.   The final branding of the web parts can be seen on the public website I recently completed called Destination Oakland.   The inside pages of the site are SharePoint publishing pages with a primary content publishing zone in the left and web parts along the right side.  This is where you will see the control adapter in action.

To create a control adapter we start with a .NET class that inherits from the System.Web.UI.Adapters.ControlAdapter base class.   We then override the Render method to modify the HTML that will be generated by the controls which are associated to the control adapter.

Below is an example control adapter used on the public SharePoint web site www.destinationoakland.com.

public class BrandingAdapter : ControlAdapter
    {
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            var webpart = Control as WebPart;
            webpart.ChromeType = PartChromeType.None;

            StringWriter stringWriter = new StringWriter();
            using (HtmlTextWriter html = new HtmlTextWriter(stringWriter))
            {
                base.Render(html);
            }

            //Start new table to format rounded corners.
            HtmlTable tblBranding = new HtmlTable();
            tblBranding.CellSpacing = 0;
            tblBranding.CellPadding = 0;
            tblBranding.Style.Add("width", "100%");

            #region Header
            HtmlTableRow trHeader = new HtmlTableRow();
            HtmlTableCell tcTopLeftCorner = new HtmlTableCell();
            tcTopLeftCorner.Style.Add("width", "6px");
            Image imgTopLeftCorner = new Image();
            imgTopLeftCorner.ImageUrl = Helper.GetSubPageImageURL(HttpContext.Current, "subheaderleft.png",true);
            tcTopLeftCorner.Controls.Add(imgTopLeftCorner);
            trHeader.Cells.Add(tcTopLeftCorner);

            HtmlTableCell tcTopCenter = new HtmlTableCell();
            tcTopCenter.Style.Add("background-image", Helper.GetSubPageImageURL(HttpContext.Current, "subheaderfill.png",false));
            tcTopCenter.Style.Add("background-repeat", "repeat-x");
            tcTopCenter.Controls.Add(new LiteralControl("<div class='destoak-webpartTitleArea'>" + webpart.Title + "</div>"));
            trHeader.Cells.Add(tcTopCenter);

            HtmlTableCell tcTopRightCorner = new HtmlTableCell();
            tcTopRightCorner.Style.Add("width", "6px");
            Image imgTopRightCorner = new Image();
            imgTopRightCorner.ImageUrl = Helper.GetSubPageImageURL(HttpContext.Current, "subheaderright.png",true);
            tcTopRightCorner.Controls.Add(imgTopRightCorner);
            trHeader.Cells.Add(tcTopRightCorner);

            tblBranding.Rows.Add(trHeader);
            #endregion

            #region Content
            HtmlTableRow trContent = new HtmlTableRow();
            HtmlTableCell tcContentLeft = new HtmlTableCell();
            tcContentLeft.Style.Add("background-image",Helper.GetTransparentImageURL(HttpContext.Current,"/_layouts/images/DestinationOakland/subpages/contentLeftShadow.png"));
            tcContentLeft.Style.Add("background-repeat", "repeat:y");
            trContent.Cells.Add(tcContentLeft);

            HtmlTableCell tcContentCenter = new HtmlTableCell();
            tcContentCenter.Style.Add("background-image", "/_layouts/images/DestinationOakland/subpages/contentFill.png");
            tcContentCenter.Style.Add("background-repeat", "repeat");
            tcContentCenter.Controls.Add(new LiteralControl("<div class='destoak-webpartBodyArea'>" + stringWriter.ToString() + "</div>"));
            trContent.Cells.Add(tcContentCenter);

            HtmlTableCell tcContentRight = new HtmlTableCell();
            tcContentRight.Style.Add("background-image", Helper.GetTransparentImageURL(HttpContext.Current,"/_layouts/images/DestinationOakland/subpages/contentRightShadow.png"));
            tcContentRight.Style.Add("background-repeat", "repeat:y");
            trContent.Cells.Add(tcContentRight);

            tblBranding.Rows.Add(trContent);
            #endregion

            #region Footer
            HtmlTableRow trFooter = new HtmlTableRow();
            HtmlTableCell tcBottomLeftCorner = new HtmlTableCell();
            tcBottomLeftCorner.Style.Add("width", "6px");
            Image imgBottomLeftCorner = new Image();
            imgBottomLeftCorner.ImageUrl = Helper.GetTransparentImageURL(HttpContext.Current,"/_layouts/images/DestinationOakland/subpages/contentleftcorner.png");
            tcBottomLeftCorner.Controls.Add(imgBottomLeftCorner);
            trFooter.Cells.Add(tcBottomLeftCorner);

            HtmlTableCell tcBottomCenter = new HtmlTableCell();
            tcBottomCenter.Style.Add("background-image", Helper.GetTransparentImageURL(HttpContext.Current,"/_layouts/images/DestinationOakland/subpages/contentbottomshadow.png"));
            tcBottomCenter.Style.Add("background-repeat", "repeat:x");
            trFooter.Cells.Add(tcBottomCenter);

            HtmlTableCell tcBottomRightCorner = new HtmlTableCell();
            tcBottomRightCorner.Style.Add("width", "6px");
            Image imgBottomRightCorner = new Image();
            imgBottomRightCorner.ImageUrl = Helper.GetTransparentImageURL(HttpContext.Current,"/_layouts/images/DestinationOakland/subpages/contentrightcorner.png");
            tcBottomRightCorner.Controls.Add(imgBottomRightCorner);
            trFooter.Cells.Add(tcBottomRightCorner);

            tblBranding.Rows.Add(trFooter);
            #endregion

            writer.Write("<div class='destoak-webpartTable'>");
            tblBranding.RenderControl(writer);
            writer.Write("</div>");

        }
    }

 

It is recommended that you build and deploy the control adapter as part of your SharePoint branding WSP installer.  For testing purposes you can manually deploy the assembly to your web front ends global assembly cache.

One last thing must be accomplished before the control adapter will work.  You need to add a browser file to the App_Browsers folder for your specific IIS SharePoint web application.  (Remember to do this on ALL web front end servers)   This file tells IIS to apply a control adapter to a specific control type while rendering the web page.   For example I may indicate that all Microsoft.SharePoint.WebPartPages.ContentEditorWebPart controls are rendered using my custom branding ControlAdapter.

By default SharePoint 2007 has a browser file called compat.browser located in the App_Browsers folder.  You could modify that file or you can create your own file that ends with the extension of .browser and place it in the App_Browsers folder.   Below is the contents of an example .browser file.  You will need to modify it to reference your specific control adapter class name and the control you wish to brand.

<browsers>
<browser refID=”Default”>
<controlAdapters>
<adapter controlType=”Microsoft.SharePoint.WebPartPages.ContentEditorWebPart”
adapterType=”MyNamespace.MyControlAdapter” />
</controlAdapters>
</browser>
</browsers>

One drawback about this method is that it is not easy to create and deploy a .browser file to all of the SharePoint web front end servers via a .WSP installer.  In part 3 of this series I will show you how to hook up a control adapter via code in the web sites masterpage.   This will simplify the process of using control adapters within SharePoint.

0 thoughts on “Using a Control Adapter for Branding Part 2”

Leave a Reply