Tuesday, February 15, 2011

Programmatically change background color of the web part header

Recently I faced with the following problem: we had requirement for particular custom web part: its header should have appropriate color (which differs from default color of all another web parts headers). During investigation I found that there are not so much solutions, which match all our requirements. It is relatively easy to change header color of all web parts on your site: you just need to play with “ms-WPHeader” style as described here. But it is not so easy to apply change on particular web parts. E.g. solution described here assumes that you should create custom class – inheritor of WebPartZone (ASP.Net WebPartZone, not Sharepoint WebPartZone which is sealed) and custom Chrome type. It is interesting solution, but with it you will need to use custom classes everywhere you want to customize header of the web part. Also it assumes that all web parts from WebPartZone will have the same chrome (which is better comparing with the case of all web parts, but not perfect still).

Another solution shows how to use Content Editor web part in order to add a style which will be uniquely identify header of one particular web part (because of using identifier “MSOZoneCell_WebPartWPQ2” in style) and apply css style to this header. This is also interesting solution – unfortunately it requires manual actions.

In ideal I would want to have control over web part header occurrence inside web part itself. And of course changes made to this web part should not affect all other web parts.

I tried several ways to achieve the result (both server side and client side). E.g. I tired to use Control Adapter for WebPartZone – where you can override Render() method and add additional styles to the header (technically web part header is “tr” element as you will show below). It works but requires modification of .browser files and complicated regex manipulation. Also overridden Render() method when you render control to the string and then replace something in this string can affect performance.

After playing a bit with client side solution (using jquery) I decided to combine server side and client side approaches.

First of all we need to add jquery reference on our master page (into head section):

   1: <SharePoint:ScriptLink ID="ScriptLink4" language="javascript" name="/_layouts/Fiskars/scripts/jquery-1.4.4.min.js" OnDemand="False" LoadAfterUI="False" Localizable="False" runat="server"/>

Then you need to add the following javascript function in the master page also:

   1: <script type="text/javascript">
   2:     function changeTitleColor(id) {
   3:         jQuery('#' + id).parentsUntil("td[id^='MSOZoneCell_']").find('tr.ms-WPHeader').css('background-color', 'Orange');
   4:     }
   5: </script>

In order to understand what it does lets consider what is actually web part in document object model:

image

Generally web part is rendered as a table (class s4-wpTopTable) with 2 rows: first row is for header, 2nd row is for web part content. The problem that inside web part we can control only those part which is rendered in 2nd row (i.e. only web part content – see picture). All another parts like header and border are controlled using web part chrome which is retrieved from WebPartZone. The good news is that inside web part we have access to it ClientID which we can use for accessing mentioned components using jquery (on the picture above it is “ctl00_m_g_72570dc0_fe27_43ca_82b9_8f324b8370eb”). Now lets return to the javascript function “changeTitleColor()” and see what it does. First of all it goes top most to the parent element which has “id” attribute beginning with “MSOZoneCell_” string:

   1: .parentsUntil("td[id^='MSOZoneCell_']")

As shown on the picture it stops on the following element:

   1: <table class="s4-wpTopTable" border="0" cellpadding="0" cellspacing="0" width="100%">

(parentUntil() method doesn’t include the element itself which matches condition). The rest is simple: we find all descendent “tr” elements which have “ms-WPHeader” class and change their css “background-color” property to the “Orange”:

   1: .find('tr.ms-WPHeader').css('background-color', 'Orange');

The only thing we need to do is to call our javascript function with identifier of the web part. It can be done by single line of code which should be added into CreateChildControls() method of your web part:

   1: protected override void CreateChildControls()
   2: {
   3:     ...
   4:     this.Controls.Add(new LiteralControl(string.Format("<script type=\"text/javascript\">changeTitleColor('{0}');</script>", this.ClientID)));
   5:     ...
   6: }

That’s all: after this you will have possibility to specify web part header color in the code of web part itself.

2 comments:

  1. you can change back ground color of a web part dynamically using java script. Add reference to SP.Js,SP.Core.debug.js,SP.Core.js,SP.debug.js in _layout mapped folder(add these files). Add a js file myscript.js add below function:


    $(function changeColor(bgcolor) {
    jQuery(".someControlClass").parentsUntil("td.s4-wpcell-plain").addClass(bgcolor);
    });


    you have someControlClass is refereed in a web control in web part as below.
    writer.WriteLine("class=\"someControlClass \" id='div-newsItem' );// add div tag unacceptable while posting
    // add other controls here
    writer.WriteLine("");//end div tag

    fire script file

    writer.WriteLine(string.Format(" >changeColor('{0}');", this.BackGroundColor));


    //again script tag was unacceptable while commenting add script tag
    In order to script work add below codes in onLoad()

    var scriptLink2 = new Microsoft.SharePoint.WebControls.ScriptLink();
    scriptLink2.Name = "/_Layouts/SP.js";
    this.Page.Header.Controls.Add(scriptLink2);

    var scriptLink3 = new Microsoft.SharePoint.WebControls.ScriptLink();
    scriptLink3.Name = "/_Layouts/SP.Core.js";
    this.Page.Header.Controls.Add(scriptLink3);

    var scriptLink6 = new Microsoft.SharePoint.WebControls.ScriptLink();
    scriptLink6.Name = "/_Layouts/MicrosoftAjax.js";
    this.Page.Header.Controls.Add(scriptLink6);

    var scriptLink4 = new Microsoft.SharePoint.WebControls.ScriptLink();
    scriptLink4.Name = "/_Layouts/myscript.js";
    scriptLink4.LoadAfterUI = false;


    Add a cssclass .css file in mapped _layout folder with and add color classes for colors

    .Red {
    background-color:Red;
    }
    .Orange {
    background-color: Orange;
    }
    .Purple {
    background-color: Purple;
    }

    ReplyDelete