Create custom field type

来源:互联网 发布:知行理工app官方 编辑:程序博客网 时间:2024/05/16 13:59
Create custom field type in WSS V3

WSS v3 supports creating custom field type with OM, and you have total control on its internal data storage, editing and display. I have tested it today by creating a custom phone number field with 3 sub-fields: country code, area code and phone number.

1. Create a ascx control and its code behind for editing

In order to make the custom field type editable in form view, we need to custom rendering user control for this new field type. At first, we need to create an ascx file with a Sharepoint RenderingTemplate control on it. See the code below.

<%@ Control Language="C#" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<SharePoint:RenderingTemplate ID="PhoneNumberFieldRendering" runat="server">
    <Template>
        +<asp:TextBox ID="txtCountryCode" runat="server" MaxLength="3" Size="3"></asp:TextBox>(<asp:TextBox ID="txtAreaCode" runat="server" MaxLength="3" Size="3"></asp:TextBox>)<asp:TextBox ID="txtNumber" runat="server" MaxLength="8" Size="8"></asp:TextBox>
    </Template>
</SharePoint:RenderingTemplate>

Then we need to implement its code behind class. The class must derives BaseFieldControl and overrides the property Value to set the three fields of a phone number into three segments in SPFieldMultiColumnValue object.

    public class PhoneNumberFieldControl : Microsoft.SharePoint.WebControls.BaseFieldControl
    {
        protected System.Web.UI.WebControls.TextBox txtCountryCode;
        protected System.Web.UI.WebControls.TextBox txtAreaCode;
        protected System.Web.UI.WebControls.TextBox txtNumberCode;

        protected override string DefaultTemplateName
        {
            get
            {
                return "PhoneNumberFieldControl";
            }
        }

        public override object Value
        {
            get
            {
                EnsureChildControls();
                Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = new Microsoft.SharePoint.SPFieldMultiColumnValue(3);
                phoneNumberValue[0] = txtCountryCode.Text.Trim();
                phoneNumberValue[1] = txtAreaCode.Text.Trim();
                phoneNumberValue[2] = txtNumberCode.Text.Trim();
                return phoneNumberValue;
            }
            set
            {
                EnsureChildControls();
                Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = value as Microsoft.SharePoint.SPFieldMultiColumnValue;
                txtCountryCode.Text = phoneNumberValue[0];
                txtAreaCode.Text = phoneNumberValue[1];
                txtNumberCode.Text = phoneNumberValue[2];
            }
        }

        public override void Focus()
        {
            EnsureChildControls();
            txtCountryCode.Focus();
        }

        protected override void CreateChildControls()
        {
            if (Field == null) return;

            base.CreateChildControls();

            if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display)
                return;

            txtCountryCode = (System.Web.UI.WebControls.TextBox)FindControl("txtCountryCode");
            if (txtCountryCode == null) throw new NullReferenceException("txtCountryCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtCountryCode.TabIndex = TabIndex;
            txtCountryCode.CssClass = CssClass;
            txtCountryCode.ToolTip = Field.Title + " Country Code";

            txtAreaCode = (System.Web.UI.WebControls.TextBox)FindControl("txtAreaCode");
            if (txtAreaCode == null) throw new NullReferenceException("txtAreaCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtAreaCode.TabIndex = TabIndex;
            txtAreaCode.CssClass = CssClass;
            txtAreaCode.ToolTip = Field.Title + " Area Code";

            txtNumberCode = (System.Web.UI.WebControls.TextBox)FindControl("txtNumberCode");
            if (txtNumberCode == null) throw new NullReferenceException("txtNumberCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtNumberCode.TabIndex = TabIndex;
            txtNumberCode.CssClass = CssClass;
            txtNumberCode.ToolTip = Field.Title + " Phone Number";
            if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.New)
            {
                txtCountryCode.Text = Field.GetCustomProperty("DefaultCountryCode").ToString();
                txtAreaCode.Text = Field.GetCustomProperty("DefaultAreaCode").ToString();
                txtNumberCode.Text = Field.GetCustomProperty("DefaultNumber").ToString();
            }
        }
    }

2. Create a custom field type class

The custom field type must inherit the base class SPField. In my test, I wrote following class derives SPFieldMultiColumn which is a subclass of SPField but supports multiple sub-columns. GetValidatedString overridden method checks the input object value and return its string value if it’s correct. GetFieldValue method is to create a SPFieldMultiColumnValue object by the input string. FieldRenderingControl property returns the user control we created in step 1.

public class PhoneNumberField : Microsoft.SharePoint.SPFieldMultiColumn
    {
        public PhoneNumberField(Microsoft.SharePoint.SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
        {
        }

        public PhoneNumberField(Microsoft.SharePoint.SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
        {
        }

        public override string GetValidatedString(object value)
        {
            Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = value as Microsoft.SharePoint.SPFieldMultiColumnValue;
            if (phoneNumberValue == null)
                return String.Empty;
            if(String.IsNullOrEmpty(phoneNumberValue[0]) || String.IsNullOrEmpty(phoneNumberValue[1]) || String.IsNullOrEmpty(phoneNumberValue[2]))
                throw new Microsoft.SharePoint.SPFieldValidationException(Microsoft.SharePoint.SPResource.GetString(Microsoft.SharePoint.Strings.MissingRequiredField));

            return value.ToString();
        }

        public override object GetFieldValue(string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = new Microsoft.SharePoint.SPFieldMultiColumnValue(value);
            return phoneNumberValue;
        }

        public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
        {
            get
            {
                Microsoft.SharePoint.WebControls.BaseFieldControl phoneNumberFieldControl = new PhoneNumberFieldControl();
                return base.FieldRenderingControl;
            }
        }
    }

3. Create custom Field Type Definition

The custom type must include a custom field type definition. It’s an XML file with file name fldtypes_*.xml. I named my phone number field definition file as fldtypes_phonenumber.xml. The detail schema is in http://msdn2.microsoft.com/en-us/library/ms415141.aspx

<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">PhoneNumber</Field>
    <Field Name="ParentType">MultiColumn</Field>
    <Field Name="TypeDisplayName">Phone Number</Field>
    <Field Name="TypeShortDescription">Phone Number</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowInListCreate">TRUE</Field>
    <Field Name="ShowInSurveyCreate">TRUE</Field>
    <Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
    <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
    <Field Name="FieldTypeClass">WSSFieldDemo.PhoneNumberField,WSSFieldDemo,Version=1.0.0.0,Culture=neutral,PublicKeyToken=5cca1e4ab4efce28</Field>
    <PropertySchema>
      <Fields>
        <Field Name="DefaultCountryCode" DisplayName="Default Country Code" MaxLength="3" DisplaySize="3" Type="Text">
          <Default>1</Default>
        </Field>
        <Field Name="DefaultAreaCode" DisplayName="Default Area Code" MaxLength="3" DisplaySize="3" Type="Text">
          <Default>416</Default>
        </Field>
        <Field Name="DefaultNumber" DisplayName="Default Phone Number" MaxLength="8" DisplaySize="8" Type="Text">
          <Default>5325554</Default>
        </Field>
      </Fields>
    </PropertySchema>
    <RenderPattern Name="DisplayPattern">
      <Switch>
        <Expr>
          <Column />
        </Expr>
        <Case Value="" />
        <Default>
          <HTML><![CDATA[+]]></HTML>
          <Column SubColumnNumber="0" HTMLEncode="TRUE" />
          <HTML><![CDATA[(]]></HTML>
          <Column SubColumnNumber="1" HTMLEncode="TRUE" />
          <HTML><![CDATA[)]]></HTML>
          <Column SubColumnNumber="2" HTMLEncode="TRUE" />
        </Default>
      </Switch>
    </RenderPattern>
  </FieldType>
</FieldTypes>

4. Deployment

The final step is to deploy the assembly, user control and the field definition xml. It includes following steps:

1. Build the solution and sign the assembly
2. Put the assembly into GAC
3. Copy the user control to /program files/.../web server extensions/12/template/controltemplates
4. Copy fldtypes_phonenumber.xml to /program files/.../web server extensions/12/template/xml/
5. iisreset.
 

原创粉丝点击