Karine Bosch’s Blog

On SharePoint

Creating a Custom List Definition based on a Generic List using a Custom Content Type


In a previous post I explained how you can define custom list templates based on existing list types like a generic list or a document library. You can also create custom list templates with additional columns.

Creating a list definition based on a generic list

There is a good post of Andrew Connell that explains the basics so I won’t repeat them here. But you can take this also one step further: you can deploy your custom list definition with custom Edit, New and/or Display form.

As explained in Andrews post, you first have to define site columns for the fields needed in your list template. A good coding practice is that you place the site columns in a different xml file in the same directory as the custom list definition. Site columns, content types and list definitions declared in CAML are deployed, together with the feature.xml, to a sub folder of the 12\TEMPLATE\FEATURES file. The sitecolumns.xml file of this sample looks like the following:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Field ID="{0081F242-5AE6-45b7-AB6C-C10C9BAC2BD0}" DisplayName="Demo Date" Name="DemoDate" StaticName="DemoDate"
         Group="Demo Columns" Type="DateTime" Format="DateOnly"
         SourceID="http://schemas.microsoft.com/sharepoint/v3" >
    <Default>[today]</Default>
  </Field>
  <Field ID="{ACF09C1D-6E62-442c-84F1-0A183D517B0A}" DisplayName="Field A" Name="FieldA" StaticName="FieldA"
         Group="Demo Columns" Type="Text" SourceID="http://schemas.microsoft.com/sharepoint/v3" />
  <Field ID="{250FD327-A419-4689-B597-6E7122EC58A9}" DisplayName="Field B" Name="FieldB" StaticName="FieldB"
         Group="Demo Columns" Type="Text" SourceID="http://schemas.microsoft.com/sharepoint/v3" />
  <Field ID="{C2F10D17-0D8D-4b21-8341-C23C0CC2E826}" DisplayName="Field C" Name="FieldC" StaticName="FieldC"
         Group="Demo Columns" Type="Text" SourceID="http://schemas.microsoft.com/sharepoint/v3" />
  <Field ID="{F3384DC2-856F-4216-8CCA-A594359296B3}" DisplayName="Field X" Name="FieldX" StaticName="FieldX"
         Group="Demo Columns" Type="Text" SourceID="http://schemas.microsoft.com/sharepoint/v3" />
  <Field ID="{705C5DBE-8ED0-462b-B0A0-E1ED3662D207}" DisplayName="Field Y" Name="FieldY" StaticName="FieldY"
         Group="Demo Columns" Type="Text" SourceID="http://schemas.microsoft.com/sharepoint/v3" />
  <Field ID="{BA20F838-EBCF-452c-9F83-FBE0BDAEE3E2}" DisplayName="Field Z" Name="FieldZ" StaticName="FieldZ"
         Group="Demo Columns" Type="Text" SourceID="http://schemas.microsoft.com/sharepoint/v3" />
</Elements>

These columns need to be added to your custom content type. It is also in the content type that you need to define your custom forms. This sample defines 2 content types and are defined in the contenttype.xml file. The <FieldRefs> element contains a <FieldRef> element for each column that is part of the content type. You must specify at a minimum the ID and the Name of the fields.

The custom forms are defined in distinct elements of the <FormTemplates> element. The ABC content type uses the standard Display form but specifies the same custom form template name that will be used by the New form and the Edit form. If necessary, also these forms can be different. The XYZ content type specifies one custom form template name for all 3 forms. The custom form templates itself must be defined in user controls (.ascx).

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType ID="0x01003643B78C87084d26BFDDC1BBE1602EEA"
               Name="Demo Content Type ABC"
               Group="Demo Content Types">
    <FieldRefs>
      <FieldRef ID="{0081F242-5AE6-45b7-AB6C-C10C9BAC2BD0}" Name="DemoDate" />
      <FieldRef ID="{ACF09C1D-6E62-442c-84F1-0A183D517B0A}" Name="FieldA" />
      <FieldRef ID="{250FD327-A419-4689-B597-6E7122EC58A9}" Name="FieldB" />
      <FieldRef ID="{C2F10D17-0D8D-4b21-8341-C23C0CC2E826}" Name="FieldC" Required="TRUE" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
        <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
          <Display>ListForm</Display>
          <Edit>ABCForm</Edit>
          <New>ABCForm</New>
        </FormTemplates>
      </XmlDocument>
    </XmlDocuments>
  </ContentType> 
  <ContentType ID="0x01004AF12652D05A4fb3A3DB0EC54425EF08"
               Name="Demo Content Type XYZ"
               Group="Demo Content Types">
    <FieldRefs>
      <FieldRef ID="{0081F242-5AE6-45b7-AB6C-C10C9BAC2BD0}" Name="DemoDate" />
      <FieldRef ID="{F3384DC2-856F-4216-8CCA-A594359296B3}" Name="FieldX" />
      <FieldRef ID="{705C5DBE-8ED0-462b-B0A0-E1ED3662D207}" Name="FieldY" />
      <FieldRef ID="{BA20F838-EBCF-452c-9F83-FBE0BDAEE3E2}" Name="FieldZ" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
        <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
          <Display>XYZForm</Display>
          <Edit>XYZForm</Edit>
          <New>XYZForm</New>
        </FormTemplates>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

 The custom form templates itself must be defined in a user control (.ascx) and must be deployed to the 12\TEMPLATE\CONTROLTEMPLATES folder. The root element is the <RenderingTemplate>. The ID is the value you specified in the <FormTemplates> element of the custom list definition. You can use the ListFieldIterator control to place all the fields on the form. But you can also define your own control template that can then be used for the fields you want to display on the form.

<%@ Control Language="C#" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
<%@ Register TagPrefix="wssuc" TagName="ToolBar" src="~/_controltemplates/ToolBar.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>
<SharePoint:RenderingTemplate ID="ABCForm" runat="server" >
    <Template>
    </script>
        <SharePoint:InformationBar ID="InformationBar1" runat="server"/>
        <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&nbsp;" runat="server">
            <Template_RightButtons>
               <SharePoint:SaveButton ID="SaveButton1" runat="server"/>
               <SharePoint:GoBackButton ID="GoBackButton1" runat="server"/>
            </Template_RightButtons>
        </wssuc:ToolBar>
   <table cellpadding=0 cellspacing=0 width=100%>
       <tr>
           <td><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></td>
       </tr>
   </table>
            <table border="0" cellpadding="5" width="100%" >
                <SharePoint:CompositeField ID="CompositeFieldDemoDate" FieldName="Demo Date" DisplaySize="50" TemplateName="CompositeField1" runat="server"/>
                <!-- Using the ListFieldIterator -->
               <SharePoint:ListFieldIterator ID="ListFieldIterator1" runat="server" />
            </table>
            <SharePoint:RequiredFieldMessage ID="RequiredFieldMessage1" runat="server"/>
            <SharePoint:InitContentType ID="InitContentType1" runat="server"/>
            <SharePoint:ItemHiddenVersion ID="ItemHiddenVersion1" runat="server"/>
   <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTblBottom" RightButtonSeparator="&nbsp;" runat="server">
     <Template_Buttons>
      <SharePoint:CreatedModifiedInfo runat="server"/>
     </Template_Buttons>
     <Template_RightButtons>
      <SharePoint:SaveButton runat="server"/>
      <SharePoint:GoBackButton runat="server"/>
     </Template_RightButtons>
   </wssuc:ToolBar>

    </Template>

</SharePoint:RenderingTemplate>
<SharePoint:RenderingTemplate ID="CompositeField1" runat="server">
    <Template>
    <TR>
        <TD width="30%" valign="top">
            <SharePoint:FieldLabel ID="FieldLabel1" runat="server"/>
        </TD>
        <TD width="70%" valign="top">
            <SharePoint:FormField ID="FormField1" runat="server"/>
        </TD>
    </TR>
    </Template>
</SharePoint:RenderingTemplate>

By using the <SharePoint:RequiredFieldMessage> control, all fields on the form are checked whether their Required property is set to TRUE. If the user doesn’t fill out a value for a required field, a message is displayed.

This is a default message. If you want to customize the message, you have to define a template within the RequiredFieldMessage control:

 <SharePoint:RequiredFieldMessage ID="RequiredFieldMessage1" runat="server">
      <CustomTemplate>
            <asp:Label ID="RequiredFieldLabel" runat="server" Text="You cannot leave this field empty." />
      </CustomTemplate>
</SharePoint:RequiredFieldMessage>

Download the sample code here.

A side node on adding fields to the list template: when you need site columns based on the Lookup type, you will have to create the site columns programmatically. Read more about this in this blog post.

6 Comments »

  1. Hi Karine,

    Thanks for the post… Saved a lot of time. I found lots of resource regarding this issue, but couldn’t make any of them work.

    Thumbs up!!!!

    Kaj

    Comment by Kaj | August 17, 2010 | Reply

  2. cool post, thank you.

    Comment by Marcell | November 4, 2010 | Reply

  3. Hi Karine

    Thanks for this post.You Saved a lot of time.
    very very very…. Thanks.

    Regards
    Venu

    Comment by venu | December 7, 2010 | Reply

  4. Hi Karine,
    my requirement is like render two lists columns in one render template.is it possible or not?please help me

    Comment by venu | December 7, 2010 | Reply

  5. Hi, thanks for the sample, i just wanted to use now the server side code on the .ascx, but the debugger will not start my Page_Load(), and no Response.Write will work. Any idea? i tried many solutions 😦

    Comment by peter | August 19, 2011 | Reply

  6. Can we do the same in SharePoint Online?

    Comment by Vijay | May 4, 2012 | Reply


Leave a comment