Thursday, March 8, 2012

Document Library and custom rendering templates

Goal was to create document library with requirement to hide fields which have 'Hidden' string in name (unfortunately I could not use ShowIn.. settings due to specific requirement from external tools integrated with SharePoint instance). My first idea was to use custom FormTemplates with custom ListFieldIterator.

Quickly, it turns out that there is a problem with registering FormTemplates for content types based on document library. SharePoint 2010 was ignoring them. The only solution I was able to find, was to disable content type inheritance. That allowed me to register my own FormTemplates.

For purpose of this example I have copied original document library content type and supplied it with two additional columns.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType ID="0x010100E9F562320B4441718C2F91D48268EFAD"
               Name="CustomContentType"
               Group="Custom Content Types"
               Description="My Content Type with hidden fields"
               Inherits="False"
               V2ListTemplateName="doclib"
               Version="0">
   <FieldRefs>
    <RemoveFieldRef ID="{67df98f4-9dec-48ff-a553-29bece9c5bf4}" Name="Attachments" />
    <RemoveFieldRef ID="{f1e020bc-ba26-443f-bf2f-b68715017bbc}" Name="WorkflowVersion" />
    <RemoveFieldRef ID="{bc91a437-52e7-49e1-8c4e-4698904b2b6d}" Name="LinkTitleNoMenu" />
    <RemoveFieldRef ID="{82642ec8-ef9b-478f-acf9-31f7d45fbc31}" Name="LinkTitle" />
    <RemoveFieldRef ID="{ae069f25-3ac2-4256-b9c3-15dbc15da0e0}" Name="GUID" />
    <RemoveFieldRef ID="{de8beacf-5505-47cd-80a6-aa44e7ffe2f4}" 
        Name="WorkflowInstanceID" />
    <FieldRef ID="{5f47e085-2150-41dc-b661-442f3027f552}" Name="SelectFilename" />
    <FieldRef ID="{8553196d-ec8d-4564-9861-3dbe931050c8}" Name="FileLeafRef" 
        Required="TRUE"/>
    <FieldRef ID="{8c06beca-0777-48f7-91c7-6da68bc07b69}" Name="Created" 
        Hidden="TRUE" />
    <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" 
        Required="FALSE" ShowInNewForm="FALSE" ShowInEditForm="TRUE"/>
    <FieldRef ID="{28cf69c5-fa48-462a-b5cd-27b6f9d2bd5f}" Name="Modified"  
        Hidden="TRUE" />
    <FieldRef ID="{822c78e3-1ea9-4943-b449-57863ad33ca9}" Name="Modified_x0020_By" 
        Hidden="FALSE"/>
    <FieldRef ID="{4dd7e525-8d6b-4cb4-9d3e-44ee25f973eb}" Name="Created_x0020_By" 
        Hidden="FALSE" />
    <!-- My fields -->
    <FieldRef ID="{C5E94AC7-EE52-4409-B219-6D6E9B33A172}" Name="MyCustomField" 
        Required="FALSE"/>
    <FieldRef ID="{B35E5E3C-A0DE-4579-A6C7-D0C83C993A6B}" Name="MyCustomFieldHidden" 
        Required="TRUE" ShowInDisplayForm="FALSE" ShowInEditForm ="TRUE" 
        ShowInListSettings="FALSE" ShowInNewForm="TRUE"/>
   </FieldRefs>
 
 ...
 
  </ContentType>  
</Elements>


In next step I have started with creation of very simple ListFieldIterator

public class CustomListFieldIterator : ListFieldIterator
{
    protected override bool IsFieldExcluded(Microsoft.SharePoint.SPField field)
    {
        if (field.InternalName.Contains("Hidden"))
        {
            return true;
        }

        return base.IsFieldExcluded(field);
    }
}


Further we need to create custom rendering template based on original one, and use newly created CustomListFieldIterator. The easiest way to achieve this is to copy original Document library form templates and perform some modifications.

First thing is to create of .ascx file in CONTROLTEMPLATES folder, and register our CustomListFieldIterator

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Register TagPrefix="CustomFieldIterator" 
Assembly="$SharePoint.Project.AssemblyFullName$" 
Namespace="CustomFieldIterator"%>


Next step is to create rendering template which will use our CustomListFieldIterator

<SharePoint:RenderingTemplate ID="MyListFieldIterator" runat="server">
    <Template>
        <CustomFieldIterator:CustomListFieldIterator runat="server"/>
    </Template>
</SharePoint:RenderingTemplate>


And use it in modified DocumentLibraryFormCore rendering template

<SharePoint:RenderingTemplate id="CustomDocumentLibraryFormCore" runat="server">
  <Template>
    <table class="ms-formtable" style="margin-top: 8px;" border="0" 
        cellpadding="0" id="formTbl" cellspacing="0" width="100%">
        <SharePoint:ItemValidationFailedMessage ID="ItemValidationFailedMessage1" 
            runat="server"/>
        <SharePoint:ChangeContentType ID="ChangeContentType1" runat="server"/>
   
   
        <SharePoint:DocumentLibraryFields TemplateName="MyListFieldIterator" 
            runat="server"/>            
   
   
        <SharePoint:ApprovalStatus ID="ApprovalStatus1" runat="server"/>
     </table>
     <SharePoint:WebPartPageMaintenanceMessage ID="WebPartPageMaintenanceMessage1" 
         runat="server"/>
     <SharePoint:DocumentTransformersInfo ID="DocumentTransformersInfo1" 
         runat="server"/>
     <table cellpadding="0" cellspacing="0" width="100%">
  <tr>
      <td class="ms-formline">
   <img src="/_layouts/images/blank.gif" width='1' height='1' alt="" />
      </td>
  </tr>
     </table> 
     <table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px">
         <tr>
      <td width="100%">
   <SharePoint:ItemHiddenVersion ID="ItemHiddenVersion1" 
                      runat="server"/>
   <SharePoint:InitContentType ID="InitContentType1" runat="server"/>
   <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" 
                     RightButtonSeparator="&#160;" runat="server">
       <Template_Buttons>
           <SharePoint:CreatedModifiedInfo runat="server"/>
       </Template_Buttons>
       <Template_RightButtons>
    <SharePoint:SaveButton runat="server"/>
    <SharePoint:GoBackButton runat="server"/>
       </Template_RightButtons>
   </wssuc:ToolBar>
      </td>
   </tr>
      </table>
   </Template>
</SharePoint:RenderingTemplate>


Now, we just need to customize DocumentLibraryForm to use our modified CustomDocumentLibraryFormCore

<SharePoint:RenderingTemplate id="CustomDocumentLibraryForm" runat="server">
  <Template>
      <SharePoint:InformationBar ID="InformationBar1" runat="server"/>
          <div id="listFormToolBarTop">
              <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" 
                  RightButtonSeparator="&#160;" runat="server">
                  <Template_RightButtons>
                      <SharePoint:SaveButton ID="SaveButton1" runat="server"/>
        <SharePoint:GoBackButton ID="GoBackButton1" runat="server"/>
           </Template_RightButtons>
       </wssuc:ToolBar>
    </div>
       <SharePoint:FormToolBar ID="FormToolBar1" runat="server"/>
   
       <SharePoint:FormComponent ID="FormComponent1" 
           TemplateName="CustomDocumentLibraryFormCore" runat="server"/>
   
  </Template>
</SharePoint:RenderingTemplate>


And we are ready to register our newly created rendering template in our content type

<XmlDocuments>
 <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
 <FormTemplates  xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
      <Display>CustomDocumentLibraryForm</Display>
      <Edit>CustomDocumentLibraryForm</Edit>
      <New>CustomDocumentLibraryForm</New>
      </FormTemplates>
  </XmlDocument>
</XmlDocuments>


After deployment New, Edit and Display forms will contain only fields which name does not contains string Hidden.

No comments:

Post a Comment