Archive

Posts Tagged ‘UserControl’

Set Content Types of default list and libraries

July 6th, 2011 Comments off

We discussed the branding of the MySite through feature stapling in previous post. Now, what if you have to change the content types of the personal and shared document libraries in the personal MySites.

Unfortunately you cannot do it from feature stapling. As your feature stapler executed before the creation of document libraries and it cannot find the document libraries to set the content type. In simple words you need to set content type after site provisioning, so your code can see the document libraries. I thought we can have a control on the master page which should run on the first time user open the site. But need to run just once.

So the solution is to use the power of SharePoint delegate controls. I created a custom control and then loaded that control in a SharePoint delegate control through a feature. This control set the content types for libraries and after completing the job it deactivated the feature. This deactivation actually removes the custom user control from SharePoint Delegate control. So it executed just once and I got the desired results from an elegant solution.

Lets start the work now……

Use the same project we created last time for MySite branding. Create a custom user control in the MySiteBranding project. Your project will look like this at this stage.

Now add a new feature to hook up your custom user control in a delegate control. Add an empty element to the project and add it to the new ContentTypeFeature. Remember to set the feature scope to Site.

Now load your custom user control to the AdditionalPageHead delegate control. Change your elements.xml file as below.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="AdditionalPageHead"
           Sequence="80"
           ControlSrc="~/_controltemplates/MysiteBranding/ContentTypeHook.ascx"></Control>
</Elements>

Here is the code for custom user control. I’m assuming that you already added the content types to the site. You can add it through feature stapler.

/// <summary>
/// Defines the MySiteHook class.
/// </summary>
public partial class MySiteHook : UserControl
{
    /// <summary>
    /// Page load method.
    /// </summary>
    /// <param name="sender">object for sender</param>
    /// <param name="e">object for events args </param>
    protected void Page_Load(object sender, EventArgs e)
    {
        SPWeb web = SPContext.Current.Web;
        SPSite site = web.Site;
        string contentTypeFeatureGuid = "6369c736-eff8-4c72-9397-b56fbc456a3b";
        string personalDocLibName = "Personal Documents";
        string sharedDocLibName = "Shared Documents";
        try
        {
            web.AllowUnsafeUpdates = true;

            // Get the SPList objects
            SPList sharedList = web.Lists[sharedDocLibName];
            SPList personalList = web.Lists[personalDocLibName];

            // Your content types has to be added to the site.
            SPContentType customContentType = web.ContentTypes["Salman Docs"];
            AddAsDefaultContentType(sharedList, customContentType);
            AddAsDefaultContentType(personalList, customContentType);
            web.Update();

            // Deactivate the feature that this control is linked to so that this code will not run again.
            bool hasFeature = false;
            foreach (SPFeature feature in site.Features)
            {
                if (feature.DefinitionId.ToString().Equals(contentTypeFeatureGuid, StringComparison.CurrentCulture))
                {
                    hasFeature = true;
                    break;
                }
            }

            if (hasFeature)
            {
                site.Features.Remove(new Guid(contentTypeFeatureGuid));
            }
        }
        finally
        {
            web.AllowUnsafeUpdates = false;
        }
    }

    /// <summary>
    /// This method add the content type as default content type.
    /// </summary>
    /// <param name="list">The SPList object.</param>
    /// <param name="customContentType">The SPContentType object.</param>
    private static void AddAsDefaultContentType(SPList list, SPContentType customContentType)
    {
        // Enable content type management on this list
        list.ContentTypesEnabled = true;
        list.Update();

        // Add the custom content type
        list.ContentTypes.Add(customContentType);
        list.Update();

        // Set it as default content type
        foreach (SPContentType contentType in list.ContentTypes)
        {
            if (contentType.Name != customContentType.Name)
            {
                list.ContentTypes.Delete(contentType.Id);
                list.Update();
            }
        }
    }
}

You have no need to make any change in the master page. If you look in the default master page, you can see that AdditionalPageHead delegate control exists there.

<SharePoint:DelegateControl runat=”server” ControlId=”AdditionalPageHead” AllowMultipleControls=”true”/>

Ok so the last thing you have to do is to add your feature to site definition. Use the existing feature stapling concept and just add this feature as well in the elements file for MySiteStapler. Your feature file will look like this now.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!-- Feature to staple with MySite host site collection -->
  <FeatureSiteTemplateAssociation Id="13719e8d-0a3d-4a1a-97a9-3e6aa9adf4c5" TemplateName="SPSMSITEHOST#0" ></FeatureSiteTemplateAssociation>
  <!-- Feature to staple with MySite personal site collection -->
  <FeatureSiteTemplateAssociation Id="13719e8d-0a3d-4a1a-97a9-3e6aa9adf4c5" TemplateName="SPSPERS#0" ></FeatureSiteTemplateAssociation>
  <!--MySiteDocs: Feature to replace content types in document libraries for MySite personal site collection-->
  <FeatureSiteTemplateAssociation Id="6369c736-eff8-4c72-9397-b56fbc456a3b" TemplateName="SPSPERS#0" ></FeatureSiteTemplateAssociation>
</Elements>

Ok all is done now just create the site with new site definition. So when you create your new MySite, it will change the master page as we discuss in the last post. Also it will load your custom control to the AdditionalPageHead delegate control. When user opens the MySite first time your control’s code will change the content type of the shared and personal document libraries. So all is done. Your project finally looks like this.

You can use this approach for anything which needs to be done after site provisioning.