In the last year and half I've been almost exclusively working on MOSS publishing projects. Any developer working on these projects becomes very familiar with site columns and content types. Site Columns and Content Types are central to WCM in MOSS but they also play a very important role throughout SharePoint as a whole. In its most simplest definition Site Columns play a very similar role that standard columns do within a list but allow for reusability throughout the site collection. Groups of site columns are then organized into Content Types and associated with other lists and functionality throughout SharePoint. Additionally they offer a great deal of flexibility such as the ability to modify content types (add & removing site columns) after creation and attaching additional functionality such as a workflow to.
With all of the advanced functionality they provide in many complex scenarios such as publishing its often overlooked that they can also be used for everyday needs such as defining a simple list with custom fields. The standard declarative approach for this is to create a feature that defines your columns within the schema.xml and a subsequent ListTemplate and/or ListInstance element to register this new list with SharePoint and optionally create an instance of that list. The functionality is very powerful but at the same time can get quite complex as modifying the schema.xml can often be cryptic and error prone, not really much fun.. trust me.
A simple alternative approach is to define site columns or even reuse out of the box or existing columns, define your content type, and bind that content type to an existing list such as a generic list. Its also possible to take existing content types, such as those use for tasks, and inherit from that content type to add your own site columns and bind that to a defined task list.
The following is one possible approach using this technique:
Step 1 : Define your feature
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
Id="F441DF54-5950-4C79-BDD1-C6960140346A"
Title="Simple List Feature"
Description="This feature Demonstrates the use of ContentTypes in lists."
Scope="Site"
Hidden="False"
Version="1.0.0.0">
<ElementManifests>
<ElementManifest Location="SiteColumns.xml" />
<ElementManifest Location="ContentTypes.xml" />
<ElementManifest Location="List.xml" />
</ElementManifests>
</Feature>
Step 2: Define your Site Columns
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field SourceID="http://schemas.microsoft.com/sharepoint/v3"
ID="{37426E2D-2F00-40E2-9BA2-EF4B1038E400}"
Name="CustomField1"
DisplayName="CustomField1"
Group="SimpleList"
Type="Text"
Required="FALSE"
Sealed="FALSE"
ReadOnly="FALSE"
Hidden="FALSE" />
<Field SourceID="http://schemas.microsoft.com/sharepoint/v3"
ID="{107D1023-54AC-43E0-8AED-65D105685184}"
Name="CustomField2"
DisplayName="CustomField2"
Group="SimpleList"
Type="Text"
Required="FALSE"
Sealed="FALSE"
ReadOnly="FALSE"
Hidden="FALSE" />
</Elements>
Step 3: Define your Content Type (this was is based on a standard list)
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentType ID="0x010026148DD4DF324cae899D48F124390550"
Name="SimpleList"
Description="Simple List Content TYpe"
Group="SimpleList">
<FieldRefs>
<FieldRef ID="{37426E2D-2F00-40E2-9BA2-EF4B1038E400}"
Name="CustomField1"
DisplayName="CustomField1"
ShowInDisplayForm="TRUE"
ShowInFileDlg="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"
ShowInEditForm="TRUE"
ReadOnlyClient="FALSE" />
<FieldRef ID="{107D1023-54AC-43E0-8AED-65D105685184}"
Name="CustomField2"
DisplayName="CustomField2"
ShowInDisplayForm="TRUE"
ShowInFileDlg="TRUE"
ShowInListSettings="TRUE"
ShowInNewForm="TRUE"
ShowInEditForm="TRUE"
ReadOnlyClient="FALSE" />
</FieldRefs>
</ContentType>
</Elements>
Step 4: Create an instance of your list and bind your content type
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ListInstance TemplateType="100"
RootWebOnly="false"
Id="CustomList"
Title="CustomList"
Url="Lists/CustomList"
OnQuickLaunch="true"
FeatureId="00BFEA71-DE22-43B2-A848-C05709900100">
</ListInstance>
<ContentTypeBinding ContentTypeId="0x010026148DD4DF324cae899D48F124390550" ListUrl="Lists/CustomList"/>
</Elements>
As you can see its pretty straight forward. Unfortunately it doesn't come without a couple gotchas. First off the default view of your list does not contain those custom columns. When you select the item you will of course see all of your columns but they aren't listed in the default view. Secondly the default content type for the list is still available to the user. In the case of a generic list the "Item" content type is still present. So when a user enters a new item they are able to select Item or your custom content type. This may not be desirable. Also if you are using the API to insert a new item into the list it will use the list's default content type instead of the one you may be expecting. Once again this may not be desirable.
To overcome these restrictions we're going to create a generic feature receiver that can be reused on any implementation using this technique.
First thing we're going to do is to make some changes to our feature to both support a feature receiver and to pass in some properties. We're going to pass in the list name and the content type name to the feature receiver code so that we do not have to hard code any values. This will be important for reuse.
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
Id="F441DF54-5950-4C79-BDD1-C6960140346A"
Title="Simple List Feature"
Description="This feature Demonstrates the use of ContentTypes in lists."
Scope="Site"
Hidden="False"
Version="1.0.0.0"
ReceiverAssembly="SimpleList, Version=1.0.0.0, Culture=neutral, PublicKeyToken=[REPLACE_THIS]"
ReceiverClass="SimpleList.SimpleListReceiver">
<ElementManifests>
<ElementManifest Location="SiteColumns.xml" />
<ElementManifest Location="ContentTypes.xml" />
<ElementManifest Location="List.xml" />
</ElementManifests>
<Properties>
<Property Key="DefaultContentType" Value="SimpleList"/>
<Property Key="ListName" Value="CustomList"/>
</Properties>
</Feature>
Next we're going to build out the feature receiver. This receiver will help us overcome two of those gotchas. First we'll set the default content type for the list and second we'll add the fields from the content type to the default view of the list.
public class SimpleListReceiver : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
SPWeb web = site.OpenWeb();
using (web)
{
string listName = properties.Feature.Properties["ListName"].ToString();
string defaultContentTypeName = properties.Feature.Properties["DefaultContentType"].ToString();
SPList list = web.Lists[listName];
SetDefaultContentType(list, defaultContentTypeName);
AddColumnsToDefaultView(list, defaultContentTypeName,web);
}
}
private void SetDefaultContentType(SPList list, string defaultContentTypeName)
{
SPContentType defaultContentType = list.ContentTypes[defaultContentTypeName];
list.ContentTypesEnabled = true;
SPFolder folder = list.RootFolder;
SPContentType[] orderedContentTypes = new SPContentType[1];
orderedContentTypes[0] = defaultContentType;
folder.UniqueContentTypeOrder = orderedContentTypes;
folder.Update();
}
private void AddColumnsToDefaultView(SPList list, string defaultContentTypeName, SPWeb web)
{
SPContentType contentType = web.ContentTypes[defaultContentTypeName];
SPView defaultView = list.DefaultView;
foreach(SPField field in contentType.Fields)
{
defaultView.ViewFields.Add(field);
}
defaultView.Update();
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties){}
public override void FeatureInstalled(SPFeatureReceiverProperties properties){}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties){}
}
With this new feature receiver at your disposal you should be able to quickly build out custom lists, take advantage of content types and site columns, and provide a good user experience by defaulting your content type and adding your new fields to the default view of the list.
I'll be uploading a zip file for download here shortly that includes this project's visual studio solution and wsp package.