Daryl Rasmussen's Not-so-random Thoughts about SharePoint Here in my world

Archive for the ‘Theming Engine’ Category

Colour your Webpart in SP 2010 with the Theming Engine

Recently I was asked to take over a webpart under development from another programmer.  The goal was to provide a Q&A list that could be displayed on a page, “Accordian” style, so that when the end user clicks on a question, the answer appears below it, similar to how the jQuery UI “Accordian” widget behaves (see http://jqueryui.com/accordion/).

As the client consisted of multiple companies under a single corporate umbrella, and each company had its own SP site with a different look and feel, they wanted the Questions displayed in a colour that complemented the current site’s colour scheme.

Disclaimer: I am Canadian. We spell the word “colour” with a “U” in it. As I’m writing this blog mostly for my own future reference, anyone not familiar with this convention should substitute the word “color” whenever they see the word “colour” throughout this post.  I will use “color” only when it is a the key word (for example, in cascading stylesheets), but not in everyday language.  For those who care, “behaviour”, “harbour” and “neighbour” are also spelled with a “U” in Canada (and I believe the UK).

Ok, so the webpart I was given to work on (remember, it was already half-written by someone else) constructs a set of HTML Div tags using a string builder in the “CreateChildControls” event, and then appends the resulting string to the webpart’s output stream, something like this:

StringBuilder sb = new StringBuilder();
Literal litContent = new Literal;
sb.Append(“<div class=’ms-rtestate-field’ style=’display: inline;’>”); 
sb.Append(“<div class=’faq-content accordion’>”);
sb.Append(“<div class=’faq-holder’>”);
// get list content and create data tags here via a call to loadAccordianList()
sb.Append(loadAccordionList());
sb.Append( “</div>” );
sb.Append(“</div>”);
sb.Append(“</div>”);
litContent.Text = sb.ToString();
this.Controls.Add(litContent);

The loadAccordianList function retrieves data from a SharePoint list.  Each list item is converted to an html description list set of tags:  the Header (where the question will be posted) is in the “dt” tag, and the Content (containing the answer to the question), is in the “dd” tag.  Each pair is wrapped in the requisit “dl” tag.  The “dt” tag has a class of “acc-item” assigned at this point as well.

A similified version of the loadAccordianList() function follows.  ProvisioningList is a string property of the webpart indicating the name of the list in SharePoint to get the data from.  Of course, in the real procedure, error checking and handling exists for such things as list not found, list empty, and so on.  It has been omitted here to keep the code simple, and because what we are mostly interested in for this discussion is the html tags being generated, not the contents that is being placed within them and how.  The actual code for retrieving the field values for the header and content of each item has similarly been ommitted from the sample below and replaced with comments indicating what is being retrieved and when.

private string loadAccordionList()
{
  StringBuilder sb = new StringBuilder();
  SPWeb web = SPContext.Current.Web;
  SPList list = web.Lists.TryGetList(ProvisioningList);
  SPQuery qry = new SPQuery();
  qry.Query = @”<OrderBy><FieldRef Name=’SortOrder’ Ascending=’TRUE’/></OrderBy>”;
  SPListItemCollection nItems = list.GetItems(qry);
  foreach (SPListItem item in nItems)
    {
      sb.Append(“<dl>”);
      sb.Append(“<dt class=’acc-item’>”);
      // Append Header (question text) here
      sb.Append(“</dt>”);
      sb.Append(“<dd class=’scriptHideOnLoad’>”);
      // Append Content (answer text) here
      sb.Append(“</dd>”);
      sb.Append(“</dl>”);here2
    }
  return sb.ToString();
}

Notice the class that is being applied to each “dt” tag.  The project when I took it over also included a custom CSS file, being deployed to the SharePoint Layouts folder.  It had a lot of stuff in it, but the important piece was the following:

.faq-content dt.acc-item { color: #ff0000; }

So the header items in the list were being shown in red.  The task at hand was to change this so that the colour was dynamically selected based on the current site’s colour scheme.  Since each site that the wepart might be deployed in could have its own Master Page, and each Master Page could reference different CSS, I had no easy way of knowing what colours might be in effect through any kind of custom branding.

However, SharePoint 2010 provides a Theming Engine. And regardless of what additional styles may or may not be being applied by the site’s Master Page, the colours from site’s current “Theme” are always available {even when the current theme is the out of the box “Default (no theme)”}, and even if those colours are being over-ridden in the Master Page for certain page elements such as the ribbon, top nav bar, etc.

To see what Theme colours are currently in effect on your site, go to your site’s “Site Settings” page, and from there, click “Site Theme”. You should see somthing similar to this:

DefaultTheme

Notice that every site has an associated set of colours (named “Text/Background – Dark 1”, “Text/Background – Light 1”, “Text/Background – Dark 2”, and so on).

It is possible in SharePoint 2010 to reference these “named” colours in your CSS. The process of buiding your CSS is fairly well documented on the Microsoft SharePoint Designer Team Blog in their Working with the SharePoint Theming Engine post.

Based on that, the first order of business is to modify the project’s existing CSS file, as follows:

.faq-content dt.acc-item { /* [ReplaceColor(themeColor:”Dark2″)] */color: #ff0000; }

I chose the “Dark2” colour from the choices listed in the above mentioned post, but could have chosen whichever of the “named” colours available I wanted to use.  As a side note, the information in the above mentioned post on re-coloring images worked as well and was employed in this webpart, but to keep this post straight forward, I’ll omit precisely how that was done.  Suffice it to say the code in the Webpart CreateChildControls that added an image to the webpart for a button to close (collapse) a section once it had been expanded, and the CSS had a line later on that looked like this to recolour that image dynamically using the Theming engine:

.faq-content .btn-close { /* [RecolorImage(themeColor:”Dark2-Medium”,method:”Tinting”)] */ background: url(/_layouts/Images/BaseAccordionWebPart/faq-arrow.gif); }

The next order of business is to move the CSS file.  The original developer was deploying this file to the SharePoint layouts folder, and while this is a perfectly acceptable approach under normal circumstances, it will not work if you want the theming enging to do the substitution and achieve a dynamicly assigned colour.  It needs to be in the “Style Library” in a “Themable” folder as described in the Microsoft post mentioned earlier.  They talk about how to put the file there using SharePoint Designer, or via the web front end.  How to do that in Visual Studio is covered well in this post in the SharePoint Tools blog.

In my case, the resulting Elements.xml file looks like this:

<?xml version=1.0encoding=utf-8?>
<Elements xmlns=http://schemas.microsoft.com/sharepoint/>
  <Module Name=StylesUrl=Style Library>
  <File Path=Styles\expandable_collapsible.css”  Url=Themable/expandable_collapsible.cssType=GhostableInLibrary />
</Module>
</Elements>

Third, as noted in the Working with the SharePoint Theming Engine post, the CSS must be properly registered.  The post mentions how to do this through SharePoint Designer, but again, not how to do it in Visual Studio.  For me, the project I took over was already registering its CSS correctly, so when I moved the file from the SharePoint “Layouts” folder to the “Style Library\Themable” folder, I just needed to update the location.  For future reference, the following call to register the CSS was invoked from the webpart’s “OnInit” event (don’t forget to do this after you invoke “base.OnInit(e)”).

CssRegistration cssRegistration = new Microsoft.SharePoint.WebControls.CssRegistration();
cssRegistration.Name = “/Style Library/Themable/expandable_collapsible.css”;
cssRegistration.After =“corev4.css”;
this.Page.Header.Controls.Add(cssRegistration);

Lastly, its time to test your webpart.  If you are like me, you will hit “F5” in visual studio to build and deploy your code to the development server, and like me, scratch your head why the text in the header is still red.  The trick here is to know that the SharePoint Theming engine only does the substituion of the selected theme colour in the CSS when the current theme is applied.  Of course, when you deploy your webpart, the theme is already applied, and so nothing happens.

To get the colours to show up, you have to re-apply the current theme.  From the front end where your webpart is deployed, go to “Site Settings” and then “Site Theme”.

On that page, click (any) one of the “Select a color…” links. Cancel the dialog that appears (so you aren’t actually changing anything) and then click Apply. The current theme will be (re-)applied, including calculating the dynamic colour for the CSS in the Style Library/Themable folder that was installed as part of the .wsp.

Also, when you are finished developing your webpart, and you are ready to deploy it to your production environment via the .wsp file, you will need to re-apply the current theme in your production environment!  You only have to do this once (when the feature containing the webpart is activated).  I do this manually…a way to do it programmatically in the feature_activated event should in theory be possible, but the client in question wasn’t interested in that and I didn’t implement it.

Tag Cloud