I'm a Feature Creature I wanted to add a single basic Custom List Template and Instance to my Feature, based on the built in Generic List. No new pages, content types, site columns or the such. Of course, the simple way is to create it in SharePoint and export the STP, but that's not what I wanted (pity this fool). I wanted to achieve the same result using my xml definitions and schema, and keep the normal feature directory structure in the 12 hive. I thought it was the simplest thing to add into a feature, but after getting annoyed with the MS Sharepoint Extensions for VS2005 not doing what I wanted (adding EditForm.aspx etc), and settling on the wonderful WSPBuilder (http://www.codeplex.com/wspbuilder, http://keutmann.blogspot.com/2008/02/visual-studio-addin-and-templates-for.html) for my solutions, I had to resort to my fellow bloggers as usual. BTW I've been told by MrCleverWorkArounds – and I believe him as always – that STSDEV is the way to go for my WSP solutions, so I'll try that out next time and report back! So firstly I'd like to thank the following for pointing me in the right general direction – all excellent reading, especially if your situation doesn't exactly match mine:
http://www.heathersolomon.com/blog/articles/1300.aspx
http://jopx.blogspot.com/2007/05/sharepoint-2007-how-to-create-custom.html
MS also provides this, but most people have issues there because of missing and ambiguous information.
I'm not going to go through all the heartache involved, but here are the salient parts that got me my result and actually displayed the fields I added. There may be things in here I didn't need to do, but life is too short for me to work out exactly which ones!So off we go.I have this structure in VS 2005. Don't worry about bloggers who say you have to have items in a flatter structure at the feature level, as we'll edit the schema appropriately later. I like this structure, and so does WSP builder, so I'd recommend you stick with it.
project – mrwaUtilsfolder – 12
folder – TEMPLATE
folder – FEATURES
folder – mrwaUtils
file – feature.xml
folder – lSettings
file – ListTemplateElements.xml
file – ListInstanceElements.xml
file – schema.xml My feature.xml looks like this: <?xml version="1.0" encoding="utf-8"?>
<Feature xmlns=http://schemas.microsoft.com/sharepoint/
Id="place-a-new-feature-GUID-here"
Scope="Site"
Hidden="FALSE"
Title="mrwaUtils Lists"
Version="1.0.0.0"
DefaultResourceFile="core"
ReceiverAssembly="mrwaUtils, Version=1.0.0.0, Culture=neutral, PublicKeyToken=hexKeyTokenValue, processorArchitecture=MSIL"
ReceiverClass="mrwaUtils.UtilsFeatureReceiver">
<ElementManifests>
<ElementManifest Location="lSettingsListTemplateElements.xml" />
<ElementManifest Location="lSettingsListInstanceElements.xml" />
<ElementFile Location="lSettingsschema.xml" />
</ElementManifests>
</Feature> The ListTemplateElements.xml file has a type of 100 (we aren't defining our own type, so don't need a number greater than 10000), I didn't want any attachments to my list so have disabled them, and I also set the feature Id as I use that to delete the list instance(s) on deactivation in the feature receiver class: <?xml version="1.0" encoding="utf-8"?>
<Elements Id="place-a-new-template-elements-GUID-here"
xmlns=http://schemas.microsoft.com/sharepoint/>
<ListTemplate Name="lSettings"
DisplayName="lSettings"
Type="100"
Description="Single list of settings, their value and if they are active"
BaseType="0"
OnQuickLaunch="TRUE"
SecurityBits="11"
Sequence="410"
Image="/_layouts/images/itgen.gif"
Unique="True"
DisableAttachments="True"
FeatureId="place-your-existing-feature-xml-GUID-here" />
</Elements>
.and the ListInstanceElements.xml file, with a single example entry populating the three fields I'll add to my schema file next: <?xml version="1.0" encoding="utf-8"?>
<Elements Id="place-a-new-instance-elements-GUID-here"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ListInstance Title="lSettings"
Description="Singleton list instance of lSettings template"
Url="Lists/lSettings"
FeatureId="place-your-existing-feature-xml-GUID-here"
OnQuickLaunch="True"
TemplateType="100">
<Data>
<Rows>
<Row>
<Field Name="Title">mrwaUtils.Log+DestTypes.EventLog</Field>
<Field Name="Value">MACHINE01</Field>
<Field Name="Active">True</Field>
</Row>
…
</Rows>
</Data>
</ListInstance>
</Elements> Notice that the URL falls under Lists/, but unlike mine, your list instance name doesn't have to be the same as your list template name.I've also set the featureId owning guid – I'm not sure if SharePoint will do this for me anyway – but with this here it is an easy task to remove any list instances from the feature in the receiver deactivating event using a common piece of code.
And now to the monster, the schema.xml
.
I found the best place to start was that installed with the MS SP extensions, so take a copy from your install. In my case that was 'C:Program FilesMicrosoft Visual Studio 8Common7IDEProjectTemplatesCacheExpCSharpSharePointListDefinition.zipListDefinitionsGenericListschema.xml'.
The first things that need changing in the schema.xml file are the List element properties:
<?xml version="1.0"?><!–
Removed for lSettings –><!– <List xmlns:ows="Microsoft SharePoint" Title="$projectname$"
FolderCreation="FALSE" Direction="$Resources:Direction;"
Url="Lists/$safeprojectname$" BaseType="0"
xmlns="http://schemas.microsoft.com/sharepoint/"> –>
<!– /Removed for lSettings –>
<!–
Added for lSettings –><!– This schema.xml is based on the generic list schema found at %ProgramFiles%Microsoft Visual Studio 8Common7IDEProjectTemplatesCacheExpCSharpSharePointListDefinition.zipListDefinitionsGenericListschema.xml –>
<List xmlns:ows="Microsoft SharePoint"
Title="lSettings"
FolderCreation="FALSE"
Direction="$Resources:Direction;"
Url="Lists/mwaUtils/lSettings"
BaseType="0"
Name="lSettings"
Id="place-your-existing-template-elements-GUID-here"
Type="100"
xmlns="http://schemas.microsoft.com/sharepoint/">
<!– /Added for lSettings –>
<!– _filecategory="ListDefinition" _filetype="Schema" _filename="schema.xml" _uniqueid="$guid10$" –>
<MetaData>
The important points in bold above are: set the list name and title to be that of your list template (which is the same as the features sub-folder we chose), add your feature name and title into the Url, place your feature TEMPLATE GUID as the Id, and add a Type in of 100. Now we'll move down a line to the content types section: <ContentTypes>
<!– Removed for lSettings –>
<!– <ContentTypeRef ID="0×01">
<Folder TargetName="Item"/>
</ContentTypeRef>
<ContentTypeRef ID="0×0120"/> –>
<!– /Removed for lSettings –>
</ContentTypes>
Just comment it all out – easy. On to the next line, Fields: <Fields>
<!– Added for lSettings –>
<!– More Info: http://msdn2.microsoft.com/en-us/library/aa543477.aspx –>
<Field List="lSettings"
Name="Value"
Title="Value"
StaticName="Value"
Type="Text"
MaxLength="255"
DisplayName="Value"
ID="{place-a-new-field-GUID-here}"
FillInChoice="TRUE"
ShowInDisplayForm="TRUE"
ShowInListSettings="TRUE"
ShowInViewForms="TRUE"
ShowInNewForm="TRUE"
Sealed="TRUE"
ReadOnly="FALSE"
ShowInEditForm="TRUE"
Viewable="TRUE"
Hidden="FALSE"
SourceID=http://schemas.microsoft.com/sharepoint/v3
ColName="nvarchar3"
RowOrdinal="0" />
<
Field List="lSettings"Name="Active"
Title="Active"
StaticName="Active"
Type="Choice"
DisplayName="Active"
ID="{place-a-new-field-GUID-here}"
FillInChoice="FALSE"
ShowInDisplayForm="TRUE"
ShowInListSettings="TRUE"
ShowInViewForms="TRUE"
ShowInNewForm="TRUE"
Sealed="TRUE"
Required="TRUE"
ReadOnly="FALSE"
ShowInEditForm="TRUE"
Viewable="TRUE"
Hidden="FALSE"
SourceID="http://schemas.microsoft.com/sharepoint/v3"
ColName="nvarchar4"
RowOrdinal="0" >
<CHOICES>
<CHOICE>Yes</CHOICE>
<CHOICE>No</CHOICE>
</CHOICES>
<MAPPINGS>
<MAPPING Value="true">Yes</MAPPING>
<MAPPING Value="false">No</MAPPING>
</MAPPINGS>
<Default>Yes</Default>
</Field>
<!– /Added for lSettings –>
</Fields> Now, I know I've set almost every property under the sun for my fields, but I was playing safe! Many of these aren't needed, but I'm not strong enough to face working out which ones.
Apart from the default title field (which we don't need to add), I wanted a simple text field called Value, and a yes no choice field called active equating to the values true/false. Have a look at http://msdn2.microsoft.com/en-us/library/ms437580.aspx for a list of types and the other properties you can set here.
OK, we're half way there with this schema monster. Now we've got to find the first of two entries called <ViewFields> in the first of our two views (titled
<View BaseViewID="0" Type="HTML">) – use find as it's about halfway through the file: <ViewFields><FieldRef Name="LinkTitleNoMenu"></FieldRef>
<!– Added for lSettings –>
<FieldRef Name="Value" ></FieldRef>
<FieldRef Name="Active" ></FieldRef>
<!– /Added for lSettings –>
</ViewFields>
All I've done is add my two field names as fieldrefs under the existing field ref entry. Move down to the next line and change the base view order (if you want to): <Query>
<OrderBy>
<!– Removed for lSettings –>
<!– <FieldRef Name="Modified" Ascending="FALSE"></FieldRef> –>
<!– /Removed for lSettings –>
<!– Added for lSettings –>
<FieldRef Name="Title" Ascending="TRUE"></FieldRef>
<!– /Added for lSettings –>
</OrderBy>
</Query>
I've replaced the modified sort with a title sort. We need to alter the next line as well to create a default AllItems view: <!– Removed for lSettings –>
<!– <View BaseViewID="1" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;" DefaultView="TRUE" ImageUrl="/_layouts/images/generic.png" Url="AllItems.aspx"><!– _locID@DisplayName="camlidCu2" _locComment=" " –>
<!– /Removed for lSettings –>
<!– Added for lSettings –>
<View BaseViewID="1"
Type="HTML"
WebPartZoneID="Main"
DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;"
DefaultView="TRUE"
ImageUrl="/_layouts/images/generic.png"
Url="AllItems.aspx"
SetupPath="pagesviewpage.aspx" >
<!– /Added for lSettings –> I added the setup path pagesviewpage.aspx – that will give us the default generated forms, rather than having to code our own. Now find the next/last <ViewFields> entry: <ViewFields>
<!– Removed for lSettings –>
<!– <FieldRef Name="Attachments"></FieldRef> –>
<!– /Removed for lSettings –>
<FieldRef Name="LinkTitle"></FieldRef>
<!– Added for lSettings –>
<FieldRef Name="Value" ></FieldRef>
<FieldRef Name="Active" ></FieldRef>
<!– /Added for lSettings –>
</ViewFields>
Once again, paste in your new fields. Put them under the existing linkTitle fieldref. Also, as I didn't want attachments, I commented out the attachments field ref. Now move to the next line in the file: <Query>
<OrderBy>
<!– Removed for lSettings –>
<FieldRef Name="ID"></FieldRef> –>
<!– /Removed for lSettings –>
<!– Added for lSettings –>
<FieldRef Name="Title" Ascending="TRUE"></FieldRef>
<!– /Added for lSettings –>
</OrderBy>
</Query>
I wanted my entries ordered by title, so adding this gives me the sort I want in the AllItems view. If you don't care about ordering don't edit that bit. Lastly, the next few lines need editing: </View>
</Views>
<Forms>
<!– Removed for lSettings –>
<!– <Form Type="DisplayForm" Url="DispForm.aspx" WebPartZoneID="Main"/>
<Form Type="EditForm" Url="EditForm.aspx" WebPartZoneID="Main"/>
<Form Type="NewForm" Url="NewForm.aspx" WebPartZoneID="Main"/> –>
<!– /Removed for lSettings –>
<!– Added for lSettings –>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pagesform.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pagesform.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pagesform.aspx" WebPartZoneID="Main" />
<!– /Added for lSettings –>
</Forms>
I've added the setup path property, as I want the system generated forms, rather than the new copies of the forms that the MS extensions give you by default – too much duplication if you don't need any changes to those!
Phew – that's it. Run `ol WSPBuilder over it, install and deploy your solution, and activate the feature. Just remember that deactivating a feature doesn't remove its list instances – so you might want to do that in the feature receiver class.
Next time, slightly delayed I'm sorry, but as promised, I'll be sharing my SPConfigUpdate code. I hope you'll like it, as it's a really cool, but rarely used, feature of SharePoint.