SharePoint Folder Icon Changer JSON MetaData Provider Control

This is a follow up to my original post on How To Change Folder Icons in SharePoint MOSS Using JavaScript.

I'd encourage you to read that post first so you have at least a basic understanding of the JavaScript involved in actually changing the folder icons.

The .Net Custom Control is much simpler. Here is the complete code C# file fully commented:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using EventPhotoGallery.Data;
using Microsoft.SharePoint;

namespace EventPhotoGallery

// Create a sub control object we can use on our ASPX page to define content type to icon mappings
Level = AspNetHostingPermissionLevel.Minimal)]
public class IconMapping : WebControl

public string ContentTypeName { get; set; }

public string IconUrl { get; set; }

public string ThumbnailUrl { get; set; }

public string ToJSON()
return string.Format("'{0}': {{ ContentTypeName: '{0}', IconUrl: '{1}', ThumbnailUrl: '{2}' }}",
ContentTypeName.QuoteEscape(), IconUrl.QuoteEscape(), ThumbnailUrl.QuoteEscape());


// Create The master web control which compiles the ASPX arguments and registers a script
[ParseChildren(true, "IconMappings")]
[ToolboxData("<{0}:FolderContentTypeIconChanger runat=server>")]
public class FolderContentTypeIconChanger : WebControl, INamingContainer
// Define a key to register the MetaData JSON object with the .Net Page Rendering process
private const string FOLDERTYPESCRIPTKEY = "FolderContentTypeIconChanger";

// A list of our MetaData Controls defined above that will be subcontrols in ASPX
private List _IconMappings = new List();

public List IconMappings { get { return _IconMappings; } set { _IconMappings = value; } }

public string ListName { get; set; }

public string RootFolder { get; set; }

protected override void OnInit(EventArgs e)
// when the AllItems.aspx page loads the current folder is always in the QueryString so let's grab it
if (!string.IsNullOrEmpty(Page.Request.QueryString["RootFolder"]))
RootFolder = Page.Request.QueryString["RootFolder"];

protected override void OnPreRender(EventArgs e)
// During prerendering let's build the JSON structure that the _AllItems object consumes.
if (!Page.ClientScript.IsStartupScriptRegistered(GetType(), FOLDERTYPESCRIPTKEY))
FOLDERTYPESCRIPTKEY, CreateScript(), true);


protected override void Render(HtmlTextWriter writer)
// Do nothing with the rendering cancel it - we don't need any html with this control the
// JavaScript has already been registered

// The worker horse - does all the work compiling the MetaData
private string CreateScript()
SPFolder folder;

// if there is no folder defined then we should use the root folder from the current context list
if (!string.IsNullOrEmpty(RootFolder))
folder = SPContext.Current.Site.RootWeb.GetFolder(RootFolder);
folder = SPContext.Current.Web.Lists[ListName].RootFolder;

// Get the SharePoint ContentType for the folder
string folderContentType = folder.Item != null ? (folder.Item.GetString(PhotoData.CONTENTTYPE) != null ?
folder.Item.GetString(PhotoData.CONTENTTYPE) : "Folder") : "Folder";

// Create a StringBuilder into which we will be appending JSON atoms
StringBuilder builder = new StringBuilder("var _FolderContentTypes = {");

// this is a custom data tier object which you're going to have to figure out on
// your own - if there is enough demand I can write another article with a
// comprehensive pattern to support folders in your document libraries
EPGData data = new EPGData();

// get all subfolders and list in json to the UI.
if (folder != null && folder.SubFolders.Count > 0)
// iterate all subfolders appending JSON Atoms to the script
foreach(SPFolder subFolder in folder.SubFolders)
data.Folder.GetContentTypeName(subFolder), subFolder.Name));
// data.Folder.GetContentTypeName(subFolder) merely returns the name of the content type
builder.Remove(builder.Length - 3, 3); // remove the last comma

builder.AppendLine(string.Format("}};\n_FolderContentTypes.RootUrl = '{0}';", SPContext.Current.Site.Url.QuoteEscape()));
// QuoteEscape is an extension method which escapes all single quotes so the JavaScript is compliant

// add the icon mappings to the control
if (IconMappings.Count > 0)
builder.AppendLine("var _FolderContentTypeIconMaps = {");
foreach (IconMapping mapping in IconMappings)
builder.AppendLine(mapping.ToJSON() + ",");

builder.AppendLine(string.Format("\nvar _CurrentFolder = {{ Name: '{0}', ContentTypeName: '{1}' }};", folder.Name.QuoteEscape(), folderContentType.QuoteEscape()));

return builder.ToString();


private string CreateFolderReference(string folderUrl, string contentTypeName, string folderName)
return string.Format("'{0}':{{FolderName: '{2}', FolderUrl:'{0}', ContentType: '{1}'}},",
folderUrl.QuoteEscape(), contentTypeName.QuoteEscape(), folderName.QuoteEscape());



So there are a couple things you still have to figure out in your own implementation, but the above is a good starting point.

Now how do you add this to the page you may say - well - first, add the assembly to the GAC.

Then within the appropriate Template Folder find your AllItems.aspx page and add a directive to register the assembly as such:

<%@ Register TagPrefix="my" Namespace="EventPhotoGallery" Assembly="EventPhotoGallery, Version=, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" %>

Next, somewhere in your ASPX code you can now add the JSON FolderContentTypeIconChanger control as such:

<my:FolderContentTypeIconChanger id="folderTypes" runat="server"
ListName="Event Photo Gallery Photographs">

<my:IconMapping ContentTypeName="Location Folder"
ThumbnailUrl="/_layouts/EventPhotoGallery/images/Location_Folder-48x48.png" />

<my:IconMapping ContentTypeName="Event Photo Folder"
ThumbnailUrl="/_layouts/EventPhotoGallery/images/Photo_folder-48x48.png" />

<my:IconMapping ContentTypeName="User Upload Folder"
ThumbnailUrl="/_layouts/EventPhotoGallery/images/Upload_Folder-48x48.png" />


I'm sure you can imagine what means what etc. but ya - this should get you going in adding custom icons to your SharePoint Folders.

Let me know if you have any other questions!

Over and Out


Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...

Is this changing the folder icon that appears for a contenttype that inherits from parent SPFolder, when you click new in document library?

Matt Stark said...

No. This changes Sharepoint icons in the List view.

I found in order to change the "New" menu icons that it's better to create a Custom Action with a custom icon & remove the existing button.