User Experience Week: Using DelegateControls to Customize the User Experience
In this final article for the SharePoint User Experience Week here on SharePoint Magazine I will talk about one of the least used, but most powerful techniques we have for customizing the SharePoint User Experience, namely the DelegateControl.
Before we get going, however, I’d like to give you a small gift for your attention through this week. Exclusive to the first 25 SharePoint Magazine readers you can use the discount code SPMUX to get a $5 discount on the first issue of Understanding SharePoint Journal. This message will be removed once the first 25 people have got their issue.
What is a DelegateControl?
A DelegateControl is a SharePoint ASP.NET control that acts as a placeholder for content or other controls. Think regular ASP.NET content placeholders but with a SharePoint Feature deployment method, meaning you can activate content on a page as you would activate any other feature in SharePoint. You might have seen these already is you’ve looked into the default.master file of a standard SharePoint installation.
A lot of SharePoint default functionality uses DelegateControls. For example, the search box is really a DelegateControl, and when you install or activate MOSS or Search Server search functionality these products uses the DelegateControl to add their own search boxes to any existing site.
Your First DelegateControl
Let’s get our hands dirty right away and see how this gets done. Also, this is the example used by MSDN to show off the Delegate Control, so you might have seen this before.
- Start by creating a new feature. If you use WSPBuilder, as explained in the “Fast Track to Feature Generation” article, use a Blank Feature item type, and set the scope to Web.
- In your elements.xml file, add the following code:
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>
<Control ControlSrc=”~/_ControlTemplates/MySearchControl.ascx”
Id=”SmallSearchInputBox”
Sequence=”1″/>
</Elements>
- Create a new file in the [12]\TEMPLATE\CONTROLTEMPLATES folder called MySearchControl.ascx. Open the file in Visual Studio
You may also deploy the .ascx user control using WSPBuilder. If so, add a folder in the Solution Explorer under 12\TEMPLATE called CONTROLTEMPLATES and add the .ascx file there.
- In the MySearchControl.ascx file, add some sample ASP.NET controls, for example:
<%@ Control Language=”C#”%>
<asp:Label ID=”Label1″ runat=”server” Text=”No search here…”></asp:Label>
- Deploy your feature and activate it before retuning to the front page. You should see something along the lines of:
The cool thing here is that once you grow tired of the support calls asking where the search box went you can simply deactivate the feature and your old search box returns.
Ok, this was a really simple, and likely completely useless example, but I just wanted to show how DelegateControls work. Let’s see if we can explore something a bit more useful.
The Structure of a SharePoint:DelegateControl
While the example above demonstrates how to use a DelegateControl and override its contents it is a simple and not very useful example. However, it serves as a starting point for the rest of this article, so I’ll explain what actually goes on.
Control types and Id
In the elements file we created earlier we added two attributes, the ControlSrc and the Id. These attributes determine which content (ControlSrc) should be placed in which DelegateControl (Id). Every DelegateControl must have a ControlId property when added to an ASP.NET page, and your Id attribute in the elements file should match this ControlId property.
The actual control is either a user control, in which case we specify the ControlSrc attribute and point it to our control, or it can be a server control, in which case we need to exchange the ControlSrc with a ControlAssembly and a ControlClass attribute:
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>
<Control ControlAssembly=”[STRONG ASSEMBLY NAME]”
ControlClass=”[CLASS NAMESPACE AND NAME]”
Id=”SmallSearchInputBox”
Sequence=”1″/>
</Elements>
You would of course exchange the [STRONG ASSEMBLY NAME] and [CLASS NAMESPACE AND NAME] with their respective values for your assembly and class. If you need help finding the strong name, just check out the post on ”How do I find the strong name of an assembly” at JustAsk or read on for a tip on how to do this if you have WSPBuilder installed.
Sequence
However, once we have defined which control to add to which DelegateControl we must understand a bit more about how the DelegateControl works to understand the remaining attribute Sequence.
The Sequence attribute basically tells SharePoint the order in which to process multiple controls. To understand how this works, consider having two features that both add content to the same DelegateControl. Now, a DelegateControl in a SharePoint page can set the AllowMultipleControls to True, in which case both the features’ content gets added, with the feature with the lowest Sequence attribute added first. The AdditionalPageHead DelegateControl is an example of a control that allows multiple controls to be added, and it is the only DelegateControl that allows this in the default.master that ships with SharePoint.
If the DelegateControl does not set the AllowMultipleControls to true, the only the feature with the lowest Sequence attribute gets added at all. The other features will not have their content added. This means that when you add a control to a DelegateControl you need to know which features have deployed content to the same DelegateControl, if any.
Adding a bit of flair
The AdditionalPageHead is a really useful DelegateControl. It is located inside the HEAD section of the default.master and it has the AllowMultipleControls set to True. This means we can add all sorts of goodies to the head using a feature.
Style sheets through DelegateControls
If you have read fellow SharePoint Magazine author Paul Culmsee’s series on SharePoint Branding you will know the difficulty facing designers looking to get their CSS added at the right time. Oh, and if you haven’t read the series it is well worth spending a few minutes reading through the first three parts at least.
Since the AdditionalPageHead DelegateControl is located right where we need to add any custom style sheets we can create our own control to add that style sheet and activate the sheet with a feature. As an added bonus, the AdditionalPageHead DelegateControl is also present in the application.master file, meaning we can add style sheets to the application pages as well, without ever touching a single Microsoft provided file.
Let’s see if we can solve Paul’s problem with a DelegateControl control.
Start with a new Visual Studio project, type WSPBuilder Project.
Add a new Feature with Receiver element. Next, add the following to your elements.xml file:
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>
<Control ControlAssembly=”[STRONG ASSEMBLY NAME]”
ControlClass=”[CLASS NAMESPACE AND NAME]”
Id=”AdditionalPageHead”
Sequence=”1″/>
</Elements>
Why use a Feature with Receiver instead of a Blank feature? Here’s a little trick, WSPBuilder does some real magic for you when building anything that requires you to input assembly information anywhere. Not only will WSPBuilder create a new class file for you, but it will enter the information you need for your Control element into the ReceiverAssembly and ReceiverClass of the feature.xml file in your new feature folder. Just copy the ReceiverAssembly attribute into the ControlAssembly and ReceiverClass into the ControlClass.
Delete the FeatureReceiver and FeatureClass from the feature.xml file, you wont need it, and it will break your feature activation.
Open the class file created by WSPBuilder for you, in the FeatureCode folder. Currently this is set to be a FeatureReceiver, so modify the file until you are left with this:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Web.UI.WebControls;
namespace StyleSheetDelegateControl
{
public class StyleSheetControl : WebControl
{
}
}
This is just the outline for our control, the rest of the code we will add to the RenderControl method in a few steps. First, let’s add a simple CSS file to add to our pages.
Add a new folder called LAYOUTS to the TEMPLATE folder in your solution explorer.
WSPBuilder will map this folder to the LAYOUTS folder in [12]\TEMPLATE. The LAYOUTS folder in [12]\TEMPLATE is again linked to the virtual path _layouts in any SharePoint site, so it makes sense to put our style sheet there.
Add a new item to the LAYOUTS folder, type StyleSheet and name it “MyCustomSheet.css” or something nice. Just don’t call it anything that is already in the LAYOUTS folder.
Your Solution Explorer should now look something like this:
Add something to the CSS file to test that your changes are actually happening. You might for example put
body
{
background: yellow;
}
into the file.
Open the class file again, and output the link to the new style sheet in the RenderControl method as such:
public override void RenderControl(System.Web.UI.HtmlTextWriter writer)
{
writer.Write(“<link rel=\”stylesheet\” type=\”text/css\” href=\”/_layouts/MyCustomSheet.css\”/>”);
}
Of course, if you named your file something else you would change the file name, but you know that. Also, I’m just linking to the root of the site collection (/_layouts/) and you might want to change that the use the SPWeb.Url property or something like that. this is just for illustrative purposes, right?
To test your new control, build your WSP file by right-cliking the project name in the Solution Explorer and choose WSPBuilder->Build WSP. To deploy, simply re-enter the WSPBuilder menu and select Deploy.
Finally, go to your favorite SharePoint site and activate the feature on the Site Settings->Site Features page. Depending on how fancy you made the CSS file you should see something like this:
Sweet! Not only have we created a method to dynamically add a CSS file to a page using a feature, but what is really cool is that this feature also works on application pages.
Nice trick, eh?
Further ideas
Now that you have seen how your can create a DelegateControl and have it run regular .NET code I hope you get inspired to take this idea further. For example you could create a solution that displays different style sheets for different users. how about displaying a style sheet only if the current user is site admin? simply replace the writer.Write line with:
if (SPContext.Current.Web.UserIsSiteAdmin)
{
writer.Write(“<link rel=\”stylesheet\” type=\”text/css\” href=\”/_layouts/MyCustomSheet.css\”/>”);
}
Now site administrators get and extra reminder that they are indeed running as site administrators and are thus capable of havoc, while regular users are get the standard interface.
Or, you could evolve this into a full-blown solution that allows users to select from a pre-defined set of styles, and have the control pick the right style sheet on an individual basis.
Before I end this article, I just want to share a few tips with you regarding utilizing DelegateControls.
Creating your own DelegateControls
DelegateControls support default content, which you can see demonstrated in the default.master in the TopNavigationDataSource control, around line 132. If no control has been added using a feature then the default content is used. When creating your own master pages, include DelegateControls for any part of the site that might potentially need to be changed, such as style sheets, navigational elements, images, etc. It is a lot easier to not use a DelegateControl when you have the option than it is to implement it later. Since the default content can contain any other ASP.NET control, all you have to do, to enable the option to override content using DelegateControls, is to wrap your content with a SharePoint:DelegateControl as such:
<SharePoint:DelegateControl runat=”server” ControlId=”[MyControlId]“>
<Template_Controls>
[YOUR CONTENT]
</Template_Controls>
</SharePoint:DelegateControl>
Then, when you need to change the content on a site, simply add a new feature that uses the Control element with the Id attribute you chose.
Second, when creating your own DelegateControls, think carefully about wheter you want to set AllowMultipleControls. If you add it, remember that _all_ features with Control elements matching your DelegateControl will be added. However, if you have good feature control it is easier to de-activate an unwanted feature than it is to add AllowMultipleControls afterwards.
The End of SharePoint User Experience Week
I do hope you have enjoyed this little tour of DelegateControls, and seen how cool it is to be able to insert content into any SharePoint page using a feature.
And, of course, I really, really hope you have enjoyed the SharePoint Magazine User Experience week, and that you now have a better understanding of the possibilities you have for creating or modifying the SharePoint User Experience. I can tell you that I have really enjoyed writing for you.
If you have ideas for future articles, comments, or questions, don’t be afraid to ask. You can contact me at furuknap<[at]>gmail.com. If your idea or question is really good you might just be featured in an article or even in the Understanding SharePoint Journal.
Now, if you’ll all excuse me, I have a development machine that needs some cleaning.
.b












Author