Overriding SharePoint List Form Templates and Using Custom Form Templates

A while ago I alluded to using custom form rendering templates to display the Item ID on a list form. I have also used them to exclude the PeopleEditor control from the OOTB spell check. What I didn’t say was how to do this at a more basic level. So with that in mind, jump aboard…

To override a SharePoint list form template you must create a user control (.ascx) that includes a RenderingTemplate element with the same ID as that you wish to override. Let’s examine that with an example, such as displaying a message on every SharePoint list item that is created throughout a SharePoint farm.

To do this we have to override the default form template associated with the Item content type. Now a content type has a template for the display form, edit form and new form. So if we find out the name/ID of this template we can create a new user control which contains a custom rendering template with the same ID. The default templates are found in %PROGRAMFILES%\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx. On opening this you will see a lot of rendering templates! So which one are we interested in? To find out esxamine the item content type – specifically the NewFormTemplateName, EditFormTemplateName and DisplayFormTemplateName. I have done this using a SharePoint connection in the Server Explorer tool in Visual Studio 2010. You could also use a tool like SharePoint Manager 2010 or write some code in a console application to write the property values out. This tells us that:

Item Content Type
DisplayFormTemplateName = "ListForm"
EditFormTemplateName = "ListForm"
NewFormTemplateName = "ListForm"

And sure enough you will find a rendering template in the DefaultTemplates.ascx file with that ID. Here it is:

<SharePoint:RenderingTemplate id="ListForm" runat="server">
	<Template>
		<span id='part1'>
			<SharePoint:InformationBar runat="server"/>
			<div id="listFormToolBarTop">
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&amp;#160;" runat="server">
					<Template_RightButtons>
						<SharePoint:NextPageButton runat="server"/>
						<SharePoint:SaveButton runat="server"/>
						<SharePoint:GoBackButton runat="server"/>
					</Template_RightButtons>
			</wssuc:ToolBar>
			</div>
			<SharePoint:FormToolBar runat="server"/>
			<SharePoint:ItemValidationFailedMessage runat="server"/>
			<table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
			<SharePoint:ChangeContentType runat="server"/>
			<SharePoint:FolderFormFields runat="server"/>
			<SharePoint:ListFieldIterator runat="server"/>
			<SharePoint:ApprovalStatus runat="server"/>
			<SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
			</table>
			<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 runat="server"/>
			<SharePoint:ParentInformationField runat="server"/>
			<SharePoint:InitContentType runat="server"/>
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#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>
		</span>
		<SharePoint:AttachmentUpload runat="server"/>
	</Template>
</SharePoint:RenderingTemplate>

So to override this

  1. Create an Empty SharePoint project in Visual Studio 2010
  2. Add a new SharePoint project item of type User Control. This will be created in a sub folder under a mapped ControlTemplates folder. I have found that for this to work correctly you need to deploy your custom template directly to the CONTROLTEMPLATES folder in the SharePoint root. To do this either move the created item one level up OR change the Deployment Location in the Properties to {SharePointRoot}\Template\ControlTemplates\.
  3. Delete the code behind that has been created and amend the mark up in the ascx to reflect this – it is not required and will prevent your template from being picked up. I recommend copying the declarations from the DefaultTemplates.ascx to ensure you have got it correct .
  4. Copy the mark up for the default form template (id=”ListForm”) from {SharePointRoot}\Template\ControlTemplates\DefaultTemplates.ascx to you newly created user control.
  5. Now make the desired changes – we will add a message at the top of the form as in the following code snippet
<SharePoint:RenderingTemplate ID="ListForm" runat="server">
	<Template>
		<span id='part1'>
            Welcome to the 3 Guys SharePoint Site!
			<SharePoint:InformationBar runat="server"/>
			<div id="listFormToolBarTop">
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&amp;#160;" runat="server">
					<Template_RightButtons>
						<SharePoint:NextPageButton runat="server"/>
						<SharePoint:SaveButton runat="server"/>
						<SharePoint:GoBackButton runat="server"/>
					</Template_RightButtons>
			</wssuc:ToolBar>
			</div>
			<SharePoint:FormToolBar runat="server"/>
			<SharePoint:ItemValidationFailedMessage runat="server"/>
			<table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
			<SharePoint:FolderFormFields runat="server"/>
			<SharePoint:ListFieldIterator runat="server"/>
			<SharePoint:ApprovalStatus runat="server"/>
			<SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
			</table>
			<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  runat="server"/>
			<SharePoint:ParentInformationField runat="server"/>
			<SharePoint:InitContentType runat="server"/>
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#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>
		</span>
		<SharePoint:AttachmentUpload runat="server"/>
	</Template>
</SharePoint:RenderingTemplate>

Now deploy your solution – make sure your project application pool is recycled to make sure the template is picked up. I find an IISRESET is worthwhile here!  :lol:

You should see something similar to

Custom Form Template

So a real world example here would be the ones mentioned in previous posts or perhaps removing the ability to change the content type of an item after creation. You will see the line in the rendering template

<SharePoint:ChangeContentType runat="server"/>

This renders the drop down control that appears when a list has content types enabled and multiple types attached. By removing this line you will no longer be able to change the content type of an item.

Custom Form Template (Edit Form)

Look no content type selector! Here is the same screen with the solution retracted.

Default Form Template (Edit Form)

The complete listing for this ascx is

<%@ Control Language="C#"   AutoEventWireup="false" %>
<%@Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
<%@Register TagPrefix="ApplicationPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.ApplicationPages.WebControls"%>
<%@Register TagPrefix="SPHttpUtility" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.Utilities"%>
<%@ Register TagPrefix="wssuc" TagName="ToolBar" src="~/_controltemplates/ToolBar.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>
<SharePoint:RenderingTemplate ID="ListForm" runat="server">
	<Template>
		<span id='part1'>
            Welcome to the 3 Guys SharePoint Site!
			<SharePoint:InformationBar runat="server"/>
			<div id="listFormToolBarTop">
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&amp;#160;" runat="server">
					<Template_RightButtons>
						<SharePoint:NextPageButton runat="server"/>
						<SharePoint:SaveButton runat="server"/>
						<SharePoint:GoBackButton runat="server"/>
					</Template_RightButtons>
			</wssuc:ToolBar>
			</div>
			<SharePoint:FormToolBar runat="server"/>
			<SharePoint:ItemValidationFailedMessage runat="server"/>
			<table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
			<SharePoint:FolderFormFields runat="server"/>
			<SharePoint:ListFieldIterator runat="server"/>
			<SharePoint:ApprovalStatus runat="server"/>
			<SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
			</table>
			<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  runat="server"/>
			<SharePoint:ParentInformationField runat="server"/>
			<SharePoint:InitContentType runat="server"/>
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#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>
		</span>
		<SharePoint:AttachmentUpload runat="server"/>
	</Template>
</SharePoint:RenderingTemplate>

Great! But what if you don’t want to override the default template for all list items? This is likely to occur where you have your own content type and you wish to assign different forms to them. This is where a custom form template with a unique ID comes in. Follow the same technique but give the rendering template a new unique ID, e.g.

<SharePoint:RenderingTemplate ID="3GuysListForm" runat="server">

The in your content type definition you can specify that you wish to use this form template. You can specify form templates for one, two or all of the new, edit and display forms. Or even different form templates for different forms. Your content type definition should contain the following XML – note that the bulk of the definition is omitted for clarity and brevity.

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

You may find issues with this, especially if you are inheriting content types. If so fear not, you can achieve this programmatically within the FeatureActivated event handler of a feature receiver.

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    SPSite site = properties.Feature.Parent as SPSite;
    if (site != null)
    {
        SPWeb root = site.RootWeb;
        // Set the custom templates
        SPContentType ctype = root.ContentTypes["3GuysContentType"];
        ctype.EditFormTemplateName = "3GuysListForm";
        ctype.DisplayFormTemplateName = "3GuysListForm";
        ctype.NewFormTemplateName = "3GuysListForm";
        ctype.Update(true);
    }
}

We can also take this whole concept further by nesting user controls and templates. If you wish to refer to an additional user control then you can just do it in the usual way by registering it with the ascx, e.g.

<%@ Register TagPrefix="3Guys" TagName="AdditionalUserControl" Src="~/_controltemplates/3Guys/AdditionalUserControl.ascx" >

You can then include it in your custom form template as follows:

<3Guys:AdditionalUserControl runat="server" />

This is a useful way to group your controls and make them available to multiple custom form templates.

Going right back to the Item ID example you can take this even further by creating a custom FormComponent. This is similar to the rendering side of creating a custom field.  To do this you would:

  1. Create a new class in your project named, for example, ListItemId
  2. Inherit from Microsoft.SharePoint.WebControls.FormComponent
  3. Override the Visible and DefaultTemplateName properties
  4. Override the render method to determine how your control should look

You will have something like:

using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;

namespace 3Guys.SharePoint.WebControls
{
    public class ListItemId: FormComponent
    {
        public override bool Visible
        {
            get
            {
                return base.ControlMode != SPControlMode.New && base.List != null && base.Visible;
            }
            set
            {
                base.Visible = value;
            }
        }

        protected override string DefaultTemplateName
        {
            get
            {
                return "3GuysListItemId";
            }
        }

        protected override void Render(System.Web.UI.HtmlTextWriter output)
        {
            if (this.Visible)
            {
                Label label = (Label)this.TemplateContainer.FindControl("ListItemId");
                label.Text = base.ItemContext.ItemId.ToString();
            }
            base.Render(output);
        }
    }
}

You also need to create the template that renders the FormComponent.

  1. Add a new rendering template to your templates ascx file
  2. Within this set out how you wish to render the form component.

This may look similar to:

<SharePoint:RenderingTemplate id="3GuysListItemId" runat="server">
    <Template>
        <table cellpadding="0" cellspacing="0">
            <tr>
                <td nowrap="nowrap" class="ms-descriptiontext">
                    Record Card ID:
                    <asp:Label ID="RecordCardId" runat="server" />
                </td>
            </tr>
        </table>
    </Template>
</SharePoint:RenderingTemplate>

You would then refer to the control in your original template in the usual way:

<3Guys:ListItemId runat="server" />

Obviously this requires the component to be registered with your template ascx

<%@ Register TagPrefix="3Guys" Assembly="3Guys.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3f41174506c64f88"
    Namespace="3Guys.SharePoint.WebControls" %>

So in this scenario your full template ascx would look like this

<%@ Control Language="C#"   AutoEventWireup="false" %>
<%@Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
<%@Register TagPrefix="ApplicationPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.ApplicationPages.WebControls"%>
<%@Register TagPrefix="SPHttpUtility" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.Utilities"%>
<%@ Register TagPrefix="wssuc" TagName="ToolBar" src="~/_controltemplates/ToolBar.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>
<%@ Register TagPrefix="3Guys" Assembly="3Guys.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3f41174506c64f88"
    Namespace="3Guys.SharePoint.WebControls" %><SharePoint:RenderingTemplate ID="ListForm" runat="server">
	<Template>
		<span id='part1'>
            Welcome to the 3 Guys SharePoint Site!
			<SharePoint:InformationBar runat="server"/>
			<div id="listFormToolBarTop">
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&amp;#160;" runat="server">
					<Template_RightButtons>
						<SharePoint:NextPageButton runat="server"/>
						<SharePoint:SaveButton runat="server"/>
						<SharePoint:GoBackButton runat="server"/>
					</Template_RightButtons>
			</wssuc:ToolBar>
			</div>
			<SharePoint:FormToolBar runat="server"/>
			<SharePoint:ItemValidationFailedMessage runat="server"/>
			<table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
			<SharePoint:FolderFormFields runat="server"/>
			<SharePoint:ListFieldIterator runat="server"/>
			<SharePoint:ApprovalStatus runat="server"/>
			<SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
			</table>
			<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  runat="server"/>
			<SharePoint:ParentInformationField runat="server"/>
			<3Guys:ListItemId runat="server" />
            <SharePoint:InitContentType runat="server"/>
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#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>
		</span>
		<SharePoint:AttachmentUpload runat="server"/>
	</Template>
</SharePoint:RenderingTemplate>
<SharePoint:RenderingTemplate id="3GuysListItemId" runat="server">
    <Template>
        <table cellpadding="0" cellspacing="0">
            <tr>
                <td nowrap="nowrap" class="ms-descriptiontext">
                    Record Card ID:
                    <asp:Label ID="RecordCardId" runat="server" />
                </td>
            </tr>
        </table>
    </Template>
</SharePoint:RenderingTemplate>

Hope you have kept up. Any feedback welcomed – if I can make this clearer then I will.

This entry was posted in SharePoint, SharePoint 2010 and tagged , , , . Bookmark the permalink.

10 Responses to Overriding SharePoint List Form Templates and Using Custom Form Templates

  1. Bill says:

    Thank you, I could not figure out why adding block in Content Type definition was not working, until I found this post! Now I know I””””m not the only one experiencing problems.
    Just curious, did you find the reason the xml override does not work on ContentType inheriting other ContentTypes?

    Thanks,
    Bill

  2. Pingback: List Form Templates « Sladescross's Blog

  3. Pingback: Sharepoint Form Customization | Sunny KB

  4. Pingback: BinaryJam » Some Extra Notes on using Rendering Templates

  5. Cesar says:

    Thanks for the helpful article. I tried to follow the instructions but jumped straight into creating a form for a new content type since I didn”t want to override the default template for all list items. And this appears to require one more step at the very end. Essentially to get my changes to appear, I had to open the site using SharePoint designer, navigate to the list using that particular content type, and edit the NewForm.aspx, EditForm.aspx, and DispForm.aspx in Advanced Mode. Towards the bottom of each file, I had to change the following from:


    ...
    0
    ListForm

    ...

    to:


    ...
    0
    CustomContentForm

    ...

    I”m not sure if that was an omission on your instructions or if I missed something in following them.

    • Cesar says:

      Well obviously that didn”t work well – the code removed all of the SharePoint tags. But anyway, within the WebPart tag, the last tag is named TemplateName and having a xmlns=”http://schemas.microsoft.com/WebPart/v2/ListForm”. Its value needs to be changed from “ListForm” (the default) to the ID of the custom form you create.

      • Cesar says:

        Problem is, each time you deploy, you have to repeat the exercise with SharePoint designer. I must be missing something :(

        • ceej says:

          Hi Cesar,

          You should not need to make any changes within SharePoint Designer for your custom form template to be picked up. At least I never have! When I get a moment I shall go through and double check my steps.

          Ceej

  6. Jane says:

    Great, that is what I am looking for.
    Thanks

  7. Max says:

    Great, that is what I am looking for , i forgot to force the template with FeatureActivated events! save me a lot of wasting time!
    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>