Replace SharePoint 2010 Search Box using Delegate Control

The Delegate Controls comes into picture when want to brand a SharePoint Site. The delegate control acts like a container control which encapsulates default content (set of child controls inside it). The default content (set of child controls associated with delegate) can be substituted by a specific control, by creating a feature. The ability to override or substitute the delegate controls brings the power & flexibility to brand SharePoint Sites.

The out-of-box SharePoint Foundation Master Page defines many controls like Top Navigation Data Source, Left Navigation Data Source, Search Box and Additional Page Head etc as delegate controls. The list is illustrated below :-

<SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" 
AllowMultipleControls="true"/>
<SharePoint:DelegateControl runat="server" ControlId="GlobalNavigation" />
<SharePoint:DelegateControl runat="server" ID="GlobalDelegate0" ControlId="GlobalSiteLink0" />

<!–

 subscribe to my blog

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
–>

<SharePoint:DelegateControl ControlId="GlobalSiteLink2" ID="GlobalDelegate2" Scope="Farm"
 runat="server" />

<SharePoint:DelegateControl runat="server" ControlId="PublishingConsole" 
Id="PublishingConsoleDelegate">
</SharePoint:DelegateControl><SharePoint:DelegateControl ControlId="GlobalSiteLink3" Scope="Farm" 
runat="server" />
<SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox" Version="4" />

<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource" 
Id="topNavigationDelegate"/>
    


The above listed delegate controls can be substituted at runtime to achieve custom branding. Let’s try to replace the Small Search Input box and see how the delegate control helps for this process. The whole idea is to define a feature for the Custom User Control with same control id mentioned in delegate and the lowest possible sequence number.

Here are the steps below :-

File —> New Project —> Empty SharePoint Project

pic1

Right Click Project –> Add New item –> User Control . Name it as ‘ReplaceSearchBox’

image

It automatically creates control templates folder and places the user control underneath that. Create any arbitrary control inside the user control. For the illustration purpose, I’ll add a Calendar Control inside the user control, to visually show a difference how the page looks after the delegate substitution.

<asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
It automatically creates control templates folder and places the user control underneath that.

Right Click Features –> Add Feature

Set the Feature Scope at Site (site-collection level)

Right Click Solution —> Add New Item –> Empty Element

We’d be leveraging Elements.xml file for the delegate substitution process. Before jumping on to the substitution lets understand how the out-of-box Search Box is defined using Feature.

searchbox

The Search Box is defined in both the Features ‘OSearchBasicFeature’ and ‘OSearchEnhancedFeature’ in the location 
C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14TEMPLATEFEATURES
The definition looks like the following :-
 
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <Control 
        Id="SmallSearchInputBox" 
        Sequence="50"
        ControlClass="Microsoft.SharePoint.Portal.WebControls.SearchBoxEx" 
ControlAssembly="Microsoft.Office.Server.Search, Version=14.0.0.0, Culture=neutral, 
PublicKeyToken=71e9bce111e9429c">

    <Property Name="GoImageUrl">/_layouts/images/gosearch15.png</Property>
    <Property Name="GoImageUrlRTL">/_layouts/images/gosearchrtl15.png</Property>
    <Property Name="GoImageActiveUrl">/_layouts/images/gosearchhover15.png</Property>
    <Property Name="GoImageActiveUrlRTL">/_layouts/images/gosearchrtlhover15.png</Property>
    <Property Name="DropDownMode">ShowDD</Property>
        <Property Name="SearchResultPageURL">/_layouts/osssearchresults.aspx</Property>
    <Property Name="ScopeDisplayGroupName"></Property>
    <Property Name="FrameType">None</Property>
    </Control>    
</Elements>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
 
Here the Id & Sequence number of the control plays an important role. 
To substitute this out-of-box SmallSearchInput box, Let’s define Elements.xml file for Feature. The id of the control should match with id of control to be replaced. 
The Sequence number should be less than the sequence number of the out-of-box control. In this case we’re assigning sequence number as 10, so that the control with the lowest
 sequence number gets precedence.
 
    <Control Id="SmallSearchInputBox" Sequence="10"
      ControlSrc ="~/_controltemplates/ReplaceSearchBox/ReplaceSearchBox.ascx">        
    </Control>
</Elements>
 
Since we’re using an user control for substitution, we need to make sure that ControlSrc attribute is defined. There is no need to define ControlClass and ControlAssembly attribute here. 
I did define all the 3 attributes, but the substitution was not happening. I’ve learnt that it’s enough to define the ControlSrc attribute itself. Do not define all 3  attributes for user control, 
the substitution will not happen. If you are using Custom Control, it makes sense to use ControlClass and ControlAssembly attribute.
The final Solution Package looks like the following :-
image

Build the Project, Package it and Deploy.

Now you can see the the custom user control with Calendar replaces the Delegate control.

Delegate Substitution

 

 Subscribe to my blog

Recycle IIS Application Pool: Cannot connect to the SharePoint site

I created a Visual Studio 2010 SharePoint Project. When i tried to build and deploy the solution from Visual Studio, i got the following error :-

Error occurred in deployment step ‘Recycle IIS Application Pool’: Cannot connect to the SharePoint site: http://samplesite/. Make sure that this is a valid URL and the SharePoint site is running on the local computer. If you moved this project to a new computer or if the URL of the SharePoint site has changed since you created the project, update the Site URL property of the project.

I realized the i’m not the administrator of the box and also did not have the access to the SharePoint content db. I fixed this issue by doing the following :-

1. Added myself as the administrator

2.Added myself to SharePoint Farm Admin Group

3. Provided DB Owner access to SharePoint Content DB

 

 Subscribe to my blog

Test Post

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;



namespace Create_Doc_Lib_Activity
{
    public partial class CreateDocumentLibrary : SequenceActivity
    {

        public static DependencyProperty UrlProperty = DependencyProperty.Register("Url", typeof(string), typeof(CreateDocumentLibrary), new PropertyMetadata(""));
        [DescriptionAttribute("Url of base site")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Optional)]
        public string Url
        {
            get
            {
                return ((string)(base.GetValue(CreateDocumentLibrary.UrlProperty)));
            }
            set
            {
                base.SetValue(CreateDocumentLibrary.UrlProperty, value);
            }
        }


        public static DependencyProperty DocLibNameProperty = DependencyProperty.Register("DocLibName", typeof(string), typeof(CreateDocumentLibrary), new PropertyMetadata(""));
        [DescriptionAttribute("Used as doc lib name")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Optional)]
        public string DocLibName
        {
            get
            {
                return ((string)(base.GetValue(CreateDocumentLibrary.DocLibNameProperty)));
            }
            set
            {
                base.SetValue(CreateDocumentLibrary.DocLibNameProperty, value);
            }
        }


        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            CreateDocLib();
            return ActivityExecutionStatus.Closed;
        }

        private void CreateDocLib()
        {
            using (SPSite sps = new SPSite(Url))
            {
                using (SPWeb spw = sps.RootWeb)
                {
                    Guid ID = spw.Lists.Add(DocLibName, DocLibName + " Document Library",
        SPListTemplateType.DocumentLibrary);
                    SPList spdl = spw.Lists[ID];
                    spdl.OnQuickLaunch = true;
                    spdl.Update();
                }
            }
        }



        public CreateDocumentLibrary()
        {
            InitializeComponent();
        }
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }