1. Field Types
As
you’ve seen, the SPFieldType enumeration can be used to determine the
type of data that a column can contain. However, it’s possible to
create custom field types that inherit from these base types and in
turn use those custom field types to create columns.
There’s
more to field types than simply specifying the type of data that a
field can contain. Let’s take a look at the objects involved before we
delve into how they interact to provide data access services for
SharePoint. The following diagram shows the key objects involved in
creating custom field types.
Inheriting from SPField
The SPField class is the base class for all field
types. Some examples of these field types include SPFieldFile, which
contains file data, and SPFieldLookup, which contains details of a
lookup to a column in another list or library. All field types must
ultimately derive from SPField either directly or indirectly. From a
data access perspective, the SPField class is the lowest level at which
we can implement custom data access code, since behind the scenes of
the SPField class, the SharePoint platform handles the appropriate
database interactions to persist the value of the object.
As of this writing, Visual Studio 2010 does not
provide a template for creating custom field controls, so let’s take a
look at how this can be done manually.
Create a new Empty SharePoint project using Visual Studio 2010, as shown next.
In the SharePoint Customization Wizard, be sure to select the Deploy As A Farm Solution option.
Add
a new class file to project named SPFieldAddress.cs. This class will be
our implementation of SPField. Add the following code:
using Microsoft.SharePoint;
namespace CustomField
{
public class SPFieldAddress : SPFieldMultiColumn
{
public SPFieldAddress(SPFieldCollection fields, string fieldName)
: base(fields, fieldName) { }
public SPFieldAddress(SPFieldCollection fields, string typeName,
string displayName): base(fields, typeName, displayName) { }
public override object GetFieldValue(string value)
{
if (!string.IsNullOrEmpty(value))
{
return new SPAddressValue(value);
}
else
{
return null;
}
}
public override string GetFieldValueAsHtml(object value)
{
if (value!=null)
{
return base.GetFieldValueAsHtml(value);
}
else
{
return "<strong>--No Address Present--</strong>";
}
}
}
}
Our
sample field will store multiple values in a single field. Rather than
write a lot of the code to implement this functionality from scratch,
we’ve based our field on SPFieldMultiColumn as opposed to SPField.
SPFieldMultiColumn stores values of type SPFieldMultiColumnValue, and
by inheriting from this class, we can create a custom data structure
for our field.
Add a new class named SPAddressValue.cs. Add the following code:
using Microsoft.SharePoint;
namespace CustomField
{
public class SPAddressValue : SPFieldMultiColumnValue
{
public SPAddressValue() : base(5) { }
public SPAddressValue(string value) : base(value) { }
public string StreetAddress
{
get { return this[0];}
set { this[0] = value;}
}
public string ApartmentNumber
{
get { return this[1];}
set { this[1] = value;}
}
public string City
{
get { return this[2];}
set { this[2] = value;}
}
public string State
{
get { return this[3];}
set { this[3] = value;}
}
public string Zip
{
get { return this[4];}
set { this[4] = value;}
}
}
}
So
that the SharePoint platform knows about our new field, we need to
create a file containing some definition XML. The file should be
deployed to %SPROOT%Template\xml. Choose Project | Add SharePoint
Mapped Folder.
Map
Template\Xml and then create a new XML file in the mapped folder named
fldtypes_FieldDemo.xml. When creating field definition files, it is
important that they be named appropriately. SharePoint loads files with
names in the format fldtypes_<whatever>.xml
Add the following XML:
<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
<FieldType>
<Field Name="TypeName">AddressField</Field>
<Field Name="ParentType">MultiColumn</Field>
<Field Name="TypeDisplayName">Demo Address Field</Field>
<Field Name="TypeShortDescription">
Demonstration custom field for entering addresses</Field>
<Field Name="UserCreatable">TRUE</Field>
<Field Name="FieldTypeClass">
CustomField.SPFieldAddress, $SharePoint.Project.AssemblyFullName$</Field>
<RenderPattern Name="HeaderPattern">
<Property Select="DisplayName" HTMLEncode="TRUE"/>
</RenderPattern>
<RenderPattern Name="DisplayPattern">
<Switch>
<Expr>
<Column/>
</Expr>
<Case Value="">
<HTML>
<![CDATA[--No Address Present--]]>
</HTML>
</Case>
<Default>
<Column SubColumnNumber="0" HTMLEncode="TRUE"/>
<HTML><![CDATA[,]]></HTML>
<Column SubColumnNumber="1" HTMLEncode="TRUE"/>
<HTML><![CDATA[,]]></HTML>
<Column SubColumnNumber="2" HTMLEncode="TRUE"/>
<HTML><![CDATA[,]]></HTML>
<Column SubColumnNumber="3" HTMLEncode="TRUE"/>
<HTML><![CDATA[,]]></HTML>
<Column SubColumnNumber="4" HTMLEncode="TRUE"/>
</Default>
</Switch>
</RenderPattern>
</FieldType>
</FieldTypes>