Hi, Aaron,
I was investigating the same issue for some time, and found a workaround, using custom control, to render field properties. I*ll try to describe my solution step-by-step.
1. Create your field definition in FLDTYPES_xxx.XML file, and add FieldEditorUserControl property to your custom field definition. Define fields for all custom properties of your custom field definition in PropertySchema section. If you don*t define some property here, you are not able to set it*s value using field.SetCustomProperty(※fieldname§) later. Looks like WSS just ignores it. In addition, you should set Hidden attribute of all Field elements in PropertySchema section to True. Otherwise, fields will be rendered in user interface.
For example, my custom property definition looks like:
<FieldType>
<Field Name="TypeName">MyCustomField</Field>
<Field Name="TypeDisplayName">My Custom Field</Field>
<Field Name="ParentType">Text</Field>
<Field Name="FieldTypeClass">MyFields.MyCustomField, MyFields, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3bf8ec1b42660c3</Field>
<Field Name="Sortable">TRUE</Field>
<Field Name="Filterable">TRUE</Field>
<Field Name="FieldEditorUserControl">/_controltemplates/MyCustomFieldControl.ascx</Field>
<PropertySchema>
<Fields>
<Field Name="MyCustomProperty" DisplayName="My Custom Property"
Type="Text" Hidden="TRUE">
</Field>
</Fields>
</PropertySchema>
...
<!--RenderPatterns -->
</FieldType>
2. The next step is to create .ascx control file in TEMPLATE\CONTROLTEMPLATES directory. In my sample it*s MyCustomFieldControl.ascx. My control is very simple:
<%@ Control Language="C#" Inherits="MyFields.SelectMyCustomProperty,MyFields, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3bf8ec1b42660c3" AutoEventWireup="false" compilationMode="Always" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl" src="~/_controltemplates/InputFormControl.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormSection" src="~/_controltemplates/InputFormSection.ascx" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %>
<wssuc:InputFormSection runat="server" id="MySections" Title="My Custom Section">
<Template_InputFormControls>
<wssuc:InputFormControl runat="server"
LabelText="My Custom Property">
<Template_Control>
<asp:DropDownList id="ctlMyCustomProperty" runat="server">
</asp:DropDownList>
</Template_Control>
</wssuc:InputFormControl>
</Template_InputFormControls>
</wssuc:InputFormSection>
As you can see, it has only one drop-down control. The idea is, that user can select some value from drop-down, and it*ll be stored in custom property of our custom field.
3. Now you should create .NET classes for your custom field type and user control. For custom field type:
public class MyCustomField : SPFieldText
{
public MyCustomField(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
this.Init();
}
public MyCustomField(SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
this.Init();
}
private void Init()
{
this.MyCustomProperty = this.GetCustomProperty("MyCustomProperty")+"";
}
private string myCustomProperty;
public string MyCustomProperty
{
get
{
return this.myCustomProperty;
}
set
{
this.myCustomProperty = value;
}
}
public override void Update()
{
this.SetCustomProperty("MyCustomProperty", this.MyCustomProperty);
base.Update();
}
}
As you can see, I*ve created string attribute and property, for my field type*s CustomProperty. In Init method, I populate it with stored custom property value. Finally, I*ve overridden Update method, to save modified custom property values to the field. I*ll describe what*s happening in WSS during field update and why all of these steps are necessary a bit later.
The code for my user control:
public class SelectMyCustomProperty : UserControl, IFieldEditor
{
protected DropDownList ctlMyCustomProperty;
private string value = "";
public void InitializeWithField(SPField field)
{
MyCustomField myField = field as MyCustomField;
if(myField != null)
this.value = myField.MyCustomProperty+"";
}
public void OnSaveChange(SPField field, bool isNew)
{
string value = this.ctlMyCustomProperty.SelectedValue;
MyCustomField myField = field as MyCustomField;
myField.MyCustomProperty = value;
}
public bool DisplayAsNewSection
{
get
{
return true;
}
}
protected override void CreateChildControls()
{
base.CreateChildControls();
// load values
ctlMyCustomProperty.Items.Add("");
ctlMyCustomProperty.Items.Add("aaa");
ctlMyCustomProperty.Items.Add("bbb");
ctlMyCustomProperty.Items.Add("ccc");
if(!this.IsPostBack)
{
ListItem item = ctlMyCustomProperty.Items.FindByText(this.value);
if(item != null)
item.Selected = true;
}
}
}
As described in SDK user control class should implement IFieldEditor interface. It has 2 methods and 1 property:
InitializeWithField 每 is called, when control is initialized;
OnSaveChanged 每 called, when user clicks OK button in field properties window;
DisplayAsNewSection 每 true if control should be displayed as new section in field properties form.
In CreateChildControls we just populate our drop-down list with some values.
The crucial point here is, not to try setting values directly to custom properties in OnSaveChange (like, myField.SetCustomProperty(※MyCustomProperty§, value)). Even if you call myField.Update() afterwards, the value won*t be saved! More precisely, it will be saved, but then it will be overwritten by current custom property value. Looks like SharePoint calls OnSaveChange in our control, then continues to update values of custom properties from other sources (and our Hidden field in PropertySchema section is one of them), and finally calls field*s Update method. That*s why we need to override Update method in our custom field class and set custom property values there 每 at that point SharePoint has done his job, and won*t change any property values.
Hope this helps!
Best regards,
Anton