Recently I worked a SharePoint project and the client wanted to create some lists with their fields. On a list, they wanted to see items grouped by a particular one of their field. Obviously that the client needed custom list definition with fields and views. At first I thought this project would be not hard but it turned out that there are tricks that I need to know about creating custom list definition. So I'd like to note down those tips here to help out others who may be in trouble like me.
Assume that you looked at
How to create custom list definition on MSDN.
1. Custom content typeThere is a important note that people usually miss (me too :-) . Let say you create content type ABC which inherits from SharePoint standard Item content type (0x01), you must do two things in your content type definition and list definition
- In content type ABC definition, remember to include fields which belong to the parent content type (Item) whereas adding custom fields for content type ABC
ContentTypeADefinition.xml
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentType ID="0x01008B7EF87D021E44fbBD83C21212A0B047"
Name="ABC ContentType"
Description="Custom ABC ContentType inherits from Item" >
<FieldRefs>
<!-- IMPORTANT: Remember to include fields that parent content type (Item for this case) uses -->
<Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" /> <!-- Title column is required by Item content type so here we include it in definition of ABC content type -->
<!-- Add custom fields here -->
<FieldRef ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747524}" />
</FieldRefs>
</ContentType>
</Elements>
- Do the same for list definition: include fields required by parent content type
schema.xml
<List xmlns:ows="Microsoft SharePoint" Title="Custom list"
Id="bc53ee2c-46b3-41ea-8deb-e75013c92eed" FolderCreation="FALSE"
Direction="$Resources:Direction;" BaseType="0">
<MetaData>
<Fields>
<!-- IMPORTANT: Add fields required by parent content type (Item) -->
<Field Name="Title" ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" DisplayName="$Resources:core,Last_Name;" Sealed="TRUE" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Title"><!-- _locID@DisplayName="camlid1" _locComment=" " -->
</Field>
<!-- Add custom fields here -->
<Field ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747524}" DisplayName="Item Name"
Name="ItemName" Type="Text" Group="Custom Columns" Required="TRUE"
SourceID="http://schemas.microsoft.com/sharepoint/v3" />
</Fields>
<!-- Other stuffs -->
</Metadata></List>
You can use
SharePoint Manager to browse the SharePoint content types and its fields for getting field info easier.
2. Custom viewIn order to define custom view, you probably need to know CAML and View schema . But there is another easier way to make it by making use of
SharePoint Manager .
First, you create a custom view on desired list on SharePoint UI.

Second, after the view is created, you use SharePoint Manager to get the view definition by copy value of property
HtmlSchemaXml in SharePoint Manager to schema.xml to make a new custom view. And there is one more important step

On the <View> element, make sure that those attributes are inserted
<View BaseViewID="2" Type="HTML" WebPartZoneID="Main" DisplayName="Custom view" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/events.png" Url="CustomView.aspx" >
- BaseViewID : this is an integer, make the attribute value uniquely with other View in schema.xml
- WebPartZoneID="Main"
- SetupPath : should be pages\viewpage.aspx so that the viewpage.aspx (this page is available in \\12\TEMPLATE\Pages\) is called when user uses your view
3. Use standard SharePoint forms in custom listNormally, a custom list definition template created by
WSS 3.0 Tools for Visual Studio usually has several files such as NewForm.aspx, DispForm.aspx, AllItems.aspx , ... And all those files are totally same as standard form in SharePoint. So if you don't have any plan to customize them, you can remove them from definition and tell SharePoint to use its standard form instead. The tip here is to add SetupPath attribute on <Form> element. Look at below xml fragment in schema.xml
schema.xml
<Forms>
<!-- I have a customized Display Form so that I keep the file DispForm.aspx in definition and SharePoint will called my customized DispForm.aspx when it renders Display Form -->
<Form Type="DisplayForm" Url="DispForm.aspx" WebPartZoneID="Main" />
<!-- For other forms, I don't change any on them so I use SetupPath attribute to tell SharePoint that calls its standard forms instead -->
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
4. Use Lookup field on list instanceYou're creating two list definition called AL and BL. In AL you have a lookup field that references to Title field in BL. But the problem is that both AL and BL are custom lists and doesn't exist in site. It means you don't have List ID of BL required for lookup field.
SharePoint support another way to solve this problem by allowing user to put an relative URL on lookup field. How nice it is :-). On our AL and BL, the trick is to provide the correct URL of BL instance in lookup field definition in AL. And the safe way to ensure the correctness of URL is that you use <ListInstance> to create a new list instead of letting user do.
ListInstances.xml
<ListInstance Id="InstanceOfBL" Title="BL List" TemplateType="10010" Url="Lists/BLInstance01">
You can see that I instruct SharePoint to create a new instance of BL template with
Lists/BLInstance01 URL. So I will provide this value into lookup list definition in AL and that solves our problem
schema.xml in AL
<Field Type="Lookup" DisplayName="Lookup Field 1" Required="FALSE" List="Lists/BLInstance01" ShowField="Title"
EnableLookup="TRUE" UnlimitedLengthInDocumentLibrary="FALSE" ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747523}"
SourceID="http://schemas.microsoft.com/sharepoint/v3" Name="LookupField1" />
The
List attribute is supposed to have a GUID but here we use relative URL (because the list instance haven't existed yet) and SharePoint accepts the url too.
Read more
here5. Create custom List Template as document libraryIf you're creating a document library as list template. Remember adding two attributes in the definition. Look at below xml fragment
<ListTemplate
Name="CustomDocLib"
DisplayName="Custom Document Library"
BaseType="1"
Type="101"
OnQuickLaunch="TRUE"
SecurityBits="11"
Sequence="1004"
DocumentTemplate="101" />
- BaseType="1" : this attribute announces SharePoint that you're creating a document library, not a list. BaseType="1" means document library, BaseType="0" means list
- DocumentTemplate="101" : this attribute makes the New Item menu item appear in New menu in toolbar. If you don't include this, you won't see New Item :-)
6. How to get the SharePoint item (SPItem) that is associated with the webpart editor in NewForm.aspx , EditForm.aspx and DispForm.aspx ?There is sometime you need to customize editor forms so that you want to retrieve the SPItem which is processed within the form (i.e. to support for your business). E.x: every time user creates new item, you want to update the lookup field in other list that refers to newly created SPItem.
So in this case, we need a customized NewForm.aspx. Create NewForm.aspx (via
Windows SharePoint Services 3.0 Tool) for the list definition. Then replace the code behind of NewForm.aspx with yours (it's created soon)
<%@ Page language="C#" MasterPageFile="~masterurl/default.master"
Inherits="MyAssembly.Features.NewCustomForm" %>
Then create new class called NewCustomForm that inherits from Microsoft.SharePoint.WebParPages.WebPartPage class
namespace MyAssembly.Features
{
public class NewCustomForm : WebPartPage
{
// This is the web part declared by default in NewForm.aspx
protected global::Microsoft.SharePoint.WebPartPages.WebPartZone Main;
}
}
}
}
Now we have a customized NewForm.aspx, before go on. Let I show you how we can retrieve the SPItem in editor first. Here the snipet code to get the SP item go with this web part and this code is going to put on our NewCustomForm class.
// By default, this page only has one webpart
// If user has customized it, we stop
if (this.Main.WebParts.Count == 1)
{
var webpartForm = this.Main.WebParts[0] as ListFormWebPart;
if (webpartForm != null)
{
var listItem = webpartForm.ItemContext.Item; // Got the SPItem going with the webpart editor
// do any thing here
// ...
}
}
You can put above code in Page_Load for example to get the item fields, or in Page_Unload to get newly created item (Note, because when a new item is saved, the page is redirected to Source param and it doesn't fire next events such as PreRender, Render so we have to use Unload event, another way is to override Dispose() method)
In short, by using ListFormWebPart.ItemContext.Item property, we can get the associated SPItem within editor and this property is very helpful in many scenarios.
Other tips