演练:创建自定义字段类型

上次修改时间: 2010年6月25日

适用范围: SharePoint Foundation 2010

本文内容
设置项目
创建验证规则类
创建自定义字段类
创建字段呈现控件
创建字段呈现模板
创建字段类型定义
创建 XSLT 样式表
生成和测试自定义字段类型
移动设备上的字段呈现与计算机上的字段呈现有何区别

本主题提供创建自定义字段类型的分步指南。您将创建一个字段,以存储 10 位数的国际标准书号 (ISBN)。

有关创建自定义字段类型和定义其呈现方式所涉及的步骤的概述,请参阅如何:创建自定义字段类型

先决条件

Microsoft Visual Studio 2010

设置项目

设置自定义字段项目

  1. 在 Visual Studio 中,创建一个"空白 SharePoint 项目"。使其成为场解决方案,而不是沙盒解决方案;并将其命名为 ISBN_Field_Type。

  2. 右键单击"解决方案资源管理器"中的项目名称并选择"属性"。

  3. 在"属性"对话框的"应用程序"选项卡上,输入 Contoso.SharePoint.ISBN_Field_Type 作为"程序集名称",Contoso.SharePoint 作为"默认命名空间"。将"目标框架"设置为 .NET Framework 3.5。

  4. 如果 Visual Studio"标准菜单"上的"解决方案平台"框未显示"任何 CPU"或"x64",请打开"生成"选项卡,然后将"平台目标"设置为"任何 CPU"或"x64"。有关进行选择的信息,请参阅如何:设置正确的目标框架和 CPU

  5. 在工具栏上单击"保存所有文件"按钮。

  6. 右键单击"解决方案资源管理器"中的项目名称,选择"添加",然后选择"新项目"。

  7. 在"添加新项目"对话框中,选择"已安装的模板"树中的"Visual C#"|"代码"(或"Visual Basic"|"代码")。

  8. 在"模板"框中选择"类",然后在"名称"框中输入 ISBN.Field.cs(或 ISBN.Field.vb)。单击"添加"。

  9. 重复上面的步骤以创建第二个类,但在"名称"框中输入 ISBN.FieldControl.cs(或 ISBN.FieldControl.vb)。单击"添加"。

  10. 以同样方式添加第三个类,并在"名称"框中输入 ISBN10ValidationRule.cs(或 ISBN10ValidationRule.vb)。单击"添加"。

  11. 在"解决方案资源管理器"中,右键单击项目名称,选择"添加",然后选择"SharePoint 映射文件夹"。

  12. 使用打开的树控件将该文件夹映射到 TEMPLATE\ControlTemplates,然后单击"确定"。

  13. 在"解决方案资源管理器"中,右键单击新 ControlTemplates 文件夹(而不是项目名称),选择"添加",再选择"新项目"。

  14. 在"添加新项目"对话框中,选择"已安装的模板"树中的"SharePoint"|"2010"。

  15. 在"模板"框中选择一个 SharePoint"用户控件",并将该 ascx 文件命名为 ISBNFieldControl.ascx。单击"添加"。Visual Studio 会自动将该文件添加到 SharePoint 解决方案清单中,并将其设置为部署到 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates。同时,它还会将程序集添加到清单中,并将其设置为部署到全局程序集缓存 (GAC)。

    提示提示

    不要通过右键单击"解决方案资源管理器"中的项目名称 来添加该"用户控件"。当通过这种方式添加"用户控件"时,Visual Studio 会将其放在 TEMPLATE\ControlTemplates 的子文件夹中,如果该控件未移动,则 Visual Studio 会将其部署到 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates 的相应子文件夹。不会添加子文件夹中的呈现模板。

  16. 删除在 ISBNFieldControl.ascx 文件下自动创建的 ISBNFieldControl.ascx.cs 和 ISBNFieldControl.ascx.designer.cs 文件(或 ISBNFieldControl.ascx.vb 和 ISBNFieldControl.ascx.designer.vb 文件)。此项目不需要它们。ISBNFieldControl.ascx 的默认内容指的就是您刚才删除的 ISBNFieldControl.ascx.cs(或 ISBNFieldControl.ascx.vb)文件,如果您此时生成项目,编译器会发出有关缺失文件的警告。可忽略以下警告:本主题后面步骤中的默认内容将发生更改。

  17. 在"解决方案资源管理器"中,右键单击项目名称,选择"添加",然后选择"SharePoint 映射文件夹"。

  18. 使用打开的树控件将该文件夹映射到 TEMPLATE\XML,然后单击"确定"。

  19. 在"解决方案资源管理器"中,右键单击新 XML 文件夹(而不是项目名称),选择"添加",再选择"新项目"。

  20. 在"添加新项目"对话框中,选择"模板"窗口中的"Visual C#"|"数据"(或"Visual Basic"|"数据"),然后选择"XML 文件"。

  21. 在"名称"框中,键入 fldtypes_ISBNField.xml,然后单击"添加"。

  22. 在"解决方案资源管理器"中,右键单击项目名称,选择"添加",然后选择"SharePoint 映射文件夹"。

  23. 使用打开的树控件将该文件夹映射到 TEMPLATE\LAYOUTS\XSL,然后单击"确定"。

  24. 在"解决方案资源管理器"中,右键单击新 XSL 文件夹(而不是项目名称),选择"添加",再选择"新项目"。

  25. 在"添加新项目"对话框中,选择"模板"窗口中的"Visual C#"|"数据"(或"Visual Basic"|"数据"),然后选择"XSLT 文件"。

  26. 在"名称"框中,键入 fldtypes_ISBNField.xsl,然后单击"添加"。注意,该名称与前面创建的文件的名称非常相似。这两个文件的用途不同,并且它们将部署到不同的文件夹。在浏览本主题时,请区分这两个文件。

  27. 右键单击"解决方案资源管理器"中的"引用"节点,单击"添加引用",然后选择"添加引用"对话框中".NET"选项卡上的"PresentationFramework.dll"。单击"确定"。(此程序集包含在以下过程中创建的 ValidationRule 类的定义。)

创建验证规则类

创建一个验证规则类

  1. 打开 ISBN10ValidationRule.cs(或 ISBN10ValidationRule.vb)文件并添加以下语句。

    using System.Text.RegularExpressions;
    using System.Windows.Controls;
    using System.Globalization;
    
    Imports System.Text.RegularExpressions
    Imports System.Windows.Controls
    Imports System.Globalization
    
  2. 更改命名空间,使其符合命名空间命名规则(该链接可能指向英文页面)中的准则。在此演练中,使用 Contoso.System.Windows.Controls。

  3. 用下面的代码替换类声明。

    public class ISBN10ValidationRule : ValidationRule
    {
        private const Int32 ISBNMODULO = 11;
    
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            String iSBN = (String)value;
            String errorMessage = "";
    
            Regex rxISBN = new Regex(@"^(?'GroupID'\d{1,5})-(?'PubPrefix'\d{1,7})-(?'TitleID'\d{1,6})-(?'CheckDigit'[0-9X]{1})$");
    
            if (!rxISBN.IsMatch(iSBN))
            {
                errorMessage = "An ISBN must have this structure:\n1-5 digit Group ID, hyphen, \n1-7 digit Publisher Prefix, hyphen, \n1-6 digit Title ID, hyphen, \n1 Check Digit (which can be \"X\" to indicate \"10\").\n";
            }
    
            if (errorMessage == "") // Matched the RegEx, so check for group length errors.
            {
                Match mISBN = rxISBN.Match(iSBN);
                GroupCollection groupsInString = mISBN.Groups;
    
                String groupID = groupsInString["GroupID"].Value;
                String pubPrefix = groupsInString["PubPrefix"].Value;
    
                if ((groupID.Length + pubPrefix.Length) >= 9)
                {
                    errorMessage = "The Group ID and Publisher Prefix can total no more than 8 digits.\n";
                }
    
                String titleID = groupsInString["TitleID"].Value;
    
                if (((groupID.Length + pubPrefix.Length) + titleID.Length) != 9)
                {
                    errorMessage = errorMessage + "The Group ID, Publisher Prefix, and \nTitle ID must total exactly 9 digits.\n";
                }
    
                if (errorMessage == "") //No group length errors, so verify the check digit algorithm.
                {
                    Int32 checkDigitValue;
                    String checkDigit = groupsInString["CheckDigit"].Value;
    
                    // To ensure check digit is one digit, "10" is represented by "X".
                    if (checkDigit == "X")
                    {
                        checkDigitValue = 10;
                    }
                    else
                    {
                        checkDigitValue = Convert.ToInt32(checkDigit);
                    }
    
                    String iSBN1st3Groups = groupID + pubPrefix + titleID; //Concatenate without the hyphens.
    
                    // Sum the weighted digits.
                    Int32 weightedSum = (10 * Convert.ToInt32(iSBN1st3Groups.Substring(0, 1))) +
                                         (9 * Convert.ToInt32(iSBN1st3Groups.Substring(1, 1))) +
                                         (8 * Convert.ToInt32(iSBN1st3Groups.Substring(2, 1))) +
                                         (7 * Convert.ToInt32(iSBN1st3Groups.Substring(3, 1))) +
                                         (6 * Convert.ToInt32(iSBN1st3Groups.Substring(4, 1))) +
                                         (5 * Convert.ToInt32(iSBN1st3Groups.Substring(5, 1))) +
                                         (4 * Convert.ToInt32(iSBN1st3Groups.Substring(6, 1))) +
                                         (3 * Convert.ToInt32(iSBN1st3Groups.Substring(7, 1))) +
                                         (2 * Convert.ToInt32(iSBN1st3Groups.Substring(8, 1))) +
                                          checkDigitValue;
    
                    Int32 remainder = weightedSum % ISBNMODULO;  // ISBN is invalid if weighted sum modulo 11 is not 0.
    
                    if (remainder != 0)
                    {
                        errorMessage = "Number fails Check Digit verification.";
                    }
    
                    if (errorMessage == "") // Passed check digit verification. 
                    {
                        return new ValidationResult(true, "This is a valid ISBN.");
                    }// end check digit verification passed
    
                    else // the check digit verification failed
                    {
                        return new ValidationResult(false, errorMessage);
                    }
    
                }// end no group length errors
    
                else // There was some error in a group length
                {
                    return new ValidationResult(false, errorMessage);
                }
    
            }// end RegEx match succeeded
    
            else // There was a RegEx match failure
            {
                  return new ValidationResult(false, errorMessage);
            }
    
        }// end Validate method 
    
    }// end ISBN10ValidationRule class
    
    Public Class ISBN10ValidationRule
        Inherits ValidationRule
        Private Const ISBNMODULO As Int32 = 11
    
        Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As CultureInfo) As ValidationResult
            Dim iSBN As String = CType(value, String)
            Dim errorMessage As String = ""
    
            Dim rxISBN As New Regex("^(?'GroupID'\d{1,5})-(?'PubPrefix'\d{1,7})-(?'TitleID'\d{1,6})-(?'CheckDigit'[0-9X]{1})$")
    
            If Not rxISBN.IsMatch(iSBN) Then
                errorMessage = "An ISBN must have this structure:" & vbLf & "1-5 digit Group ID, hyphen, " & vbLf & "1-7 digit Publisher Prefix, hyphen, " & vbLf & "1-6 digit Title ID, hyphen, " & vbLf & "1 Check Digit (which can be ""X"" to indicate ""10"")." & vbLf
            End If
    
            If errorMessage = "" Then ' Matched the RegEx, so check for group length errors.
                Dim mISBN As Match = rxISBN.Match(iSBN)
                Dim groupsInString As GroupCollection = mISBN.Groups
    
                Dim groupID As String = groupsInString("GroupID").Value
                Dim pubPrefix As String = groupsInString("PubPrefix").Value
    
                If (groupID.Length + pubPrefix.Length) >= 9 Then
                    errorMessage = "The Group ID and Publisher Prefix can total no more than 8 digits." & vbLf
                End If
    
                Dim titleID As String = groupsInString("TitleID").Value
    
                If ((groupID.Length + pubPrefix.Length) + titleID.Length) <> 9 Then
                    errorMessage = errorMessage & "The Group ID, Publisher Prefix, and " & vbLf & "Title ID must total exactly 9 digits." & vbLf
                End If
    
                If errorMessage = "" Then 'No group length errors, so verify the check digit algorithm.
                    Dim checkDigitValue As Int32
                    Dim checkDigit As String = groupsInString("CheckDigit").Value
    
                    ' To ensure check digit is one digit, "10" is represented by "X".
                    If checkDigit = "X" Then
                        checkDigitValue = 10
                    Else
                        checkDigitValue = Convert.ToInt32(checkDigit)
                    End If
    
                    Dim iSBN1st3Groups As String = groupID & pubPrefix & titleID 'Concatenate without the hyphens.
    
                    ' Sum the weighted digits.
                    Dim weightedSum As Int32 = (10 * Convert.ToInt32(iSBN1st3Groups.Substring(0, 1))) + (9 * Convert.ToInt32(iSBN1st3Groups.Substring(1, 1))) + (8 * Convert.ToInt32(iSBN1st3Groups.Substring(2, 1))) + (7 * Convert.ToInt32(iSBN1st3Groups.Substring(3, 1))) + (6 * Convert.ToInt32(iSBN1st3Groups.Substring(4, 1))) + (5 * Convert.ToInt32(iSBN1st3Groups.Substring(5, 1))) + (4 * Convert.ToInt32(iSBN1st3Groups.Substring(6, 1))) + (3 * Convert.ToInt32(iSBN1st3Groups.Substring(7, 1))) + (2 * Convert.ToInt32(iSBN1st3Groups.Substring(8, 1))) + checkDigitValue
    
                    Dim remainder As Int32 = weightedSum Mod ISBNMODULO ' ISBN is invalid if weighted sum modulo 11 is not 0.
    
                    If remainder <> 0 Then
                        errorMessage = "Number fails Check Digit verification."
                    End If
    
                    If errorMessage = "" Then ' Passed check digit verification.
                        Return New ValidationResult(True, "This is a valid ISBN.") ' end check digit verification passed
    
                    Else ' the check digit verification failed
                        Return New ValidationResult(False, errorMessage)
                    End If
                    ' end no group length errors
    
                Else ' There was some error in a group length
                    Return New ValidationResult(False, errorMessage)
                End If
                ' end RegEx match succeeded
    
            Else ' There was a RegEx match failure
                Return New ValidationResult(False, errorMessage)
            End If
    
        End Function ' end Validate method
    
    End Class ' end ISBN10ValidationRule class
    

    您刚创建的验证规则类包含所有详细验证逻辑。有关验证规则类的详细信息,请参阅 System.Text.RegularExpressionsValidationRule

创建自定义字段类

创建一个自定义字段类

  1. 打开 ISBN.Field.cs(或 ISBN.Field.vb)文件。

  2. 添加以下语句。

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Security;
    
    using System.Windows.Controls;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    
    Imports Microsoft.SharePoint
    Imports Microsoft.SharePoint.WebControls
    Imports Microsoft.SharePoint.Security
    
    Imports System.Windows.Controls
    Imports System.Globalization
    Imports System.Runtime.InteropServices
    Imports System.Security.Permissions
    
  3. 添加以下语句。这样,您的类实现便可引用您在后面的步骤中创建的其他类。在创建这些类之前,您可能会看到有关这些语句的编译器警告。

    using Contoso.SharePoint.WebControls;
    using Contoso.System.Windows.Controls;
    
    Imports Contoso.SharePoint.WebControls
    Imports Contoso.System.Windows.Controls
    
  4. 确保该命名空间为 Contoso.SharePoint。

  5. 应确保将该类命名为 ISBNField,并更改其声明,以指定它是从 SPFieldText 继承的。

    public class ISBNField : SPFieldText
    {
    }
    
    Public Class ISBNField
        Inherits SPFieldText
    
    End Class
    
  6. 为类添加以下所需的构造函数。

    public ISBNField(SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
    {
    }
    
    public ISBNField(SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
    {
    }
    
    Public Sub New(fields as SPFieldCollection, fieldname as String)
            MyBase.New(fields, fieldName)
    End Sub
    
    Public Sub New(fields as SPFieldCollection, typeName as String, displayName as String)
            MyBase.New(fields, typeName, displayName)
    End Sub
    
  7. FieldRenderingControl 的以下重写添加到该类中。ISBNFieldControl 是在后面的步骤中创建的类。

    public override BaseFieldControl FieldRenderingControl
    {
         [SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
        get
        {
            BaseFieldControl fieldControl = new ISBNFieldControl();
            fieldControl.FieldName = this.InternalName;
    
            return fieldControl;
        }
    }
    
    Public Overrides ReadOnly Property FieldRenderingControl() As BaseFieldControl
        Get
            Dim fieldControl As BaseFieldControl = New ISBNFieldControl()
            fieldControl.FieldName = Me.InternalName
            Return fieldControl
        End Get
    End Property
    
  8. GetValidatedString 方法的以下重写添加到 ISBNField 类中:

    public override string GetValidatedString(object value)
    {
        if ((this.Required == true)
           &&
           ((value == null)
            ||
           ((String)value == "")))
        {
            throw new SPFieldValidationException(this.Title 
                + " must have a value.");
        }
        else
        {
            ISBN10ValidationRule rule = new ISBN10ValidationRule();
            ValidationResult result = rule.Validate(value, CultureInfo.InvariantCulture);
    
            if (!result.IsValid)
            {
                throw new SPFieldValidationException((String)result.ErrorContent);
            }
            else
            {
                return base.GetValidatedString(value);
            }
        }
    }// end GetValidatedString
    
    Public Overrides Function GetValidatedString(ByVal value As Object) As String
        If (Me.Required = True) AndAlso ((value Is Nothing) OrElse (CType(value, String) = "")) Then
            Throw New SPFieldValidationException(Me.Title & " must have a value.")
        Else
            Dim rule As New ISBN10ValidationRule()
            Dim result As ValidationResult = rule.Validate(value, cultureInfo.InvariantCulture)
    
            If Not result.IsValid Then
                Throw New SPFieldValidationException(CType(result.ErrorContent, String))
            Else
                Return MyBase.GetValidatedString(value)
            End If
        End If
    End Function ' end GetValidatedString
    

    此重写说明了 GetValidatedString 重写的通用模式:

    • GetValidatedString 方法的重写会检查该字段是否是必需的,如果是,则重写的方法会在值为 null 或为空 String 时引发 SPFieldValidationException 异常。如果用户尝试保存要创建或编辑的列表项,则"新建项目"和"编辑文档"页面会捕获该异常。在这种情况下,页面仍保持打开状态,但该异常的 Message() 属性会导致在空字段的下方显示一则错误消息。

    • 当值无效时,重写 GetValidatedString 会引发 SPFieldValidationException,从而导致在无效字段下方显示错误消息。

    • 如果值通过自定义验证,则 GetValidatedString 重写会调用基 GetValidatedString

  9. 保存并关闭该文件。

创建字段呈现控件

创建字段呈现控件

  1. 打开 ISBN.FieldControl.cs(或 ISBN.FieldControl.vb)文件。

  2. 添加以下语句。

    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    using System.Runtime.InteropServices;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    
    Imports System.Web
    Imports System.Web.UI
    Imports System.Web.UI.WebControls
    
    Imports System.Runtime.InteropServices
    Imports Microsoft.SharePoint
    Imports Microsoft.SharePoint.WebControls
    
  3. 将命名空间更改为 Contoso.SharePoint.WebControls。

  4. 应确保将该类命名为 ISBNFieldControl,并更改其声明,以指定它是从 TextField 继承的。

    public class ISBNFieldControl : TextField
    {
    }
    
    Public Class ISBNFieldControl 
        Inherits TextField
    
    End Class
    
  5. 如果将在每个 ISBN 编号之前添加"ISBN"前缀的 ASP.NET Label Web 控件的呈现模式为"新建"或"编辑",请为该控件添加一个受保护的字段。不需要添加受保护的 TextBox 字段来保存 ISBN 编号本身,因为自定义 ISBNFieldControl 从 TextField 继承该字段。

    protected Label ISBNPrefix;
    
    Protected Label ISBNPrefix
    
  6. 为将在"显示"模式中呈现字段的当前值的 ASP.NET Label Web 控件添加其他受保护字段。

    protected Label ISBNValueForDisplay;
    
    Protected Label ISBNValueForDisplay
    
  7. 接下来,添加 DefaultTemplateName 属性的以下重写。您分配给此属性的 StringRenderingTemplate 对象的 ID,您将在后面的步骤中将该对象添加到以前创建的 .ascx 文件中。(项目完成后,该文件会部署到 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\CONTROLTEMPLATES 文件夹。)如果不重写 ControlTemplateTemplateTemplateName,则会按以下方式调用 RenderingTemplateControlTemplate 将返回 Template,然后后者将返回由 TemplateName 命名的任意 RenderingTemplateTemplate 属性。最后,TemplateName 的 get 取值函数将返回 DefaultTemplateName。在更复杂的情况下,例如,您具有一些用于"新建"和"编辑"模式的单独模板,则需要重写前面的一个或多个属性,可能还需要重写 AlternateTemplateNameDefaultAlternateTemplateName 属性。

    protected override string DefaultTemplateName
    {
        get
        {
            if (this.ControlMode == SPControlMode.Display)
            {
                return this.DisplayTemplateName;
            }
            else
            {
                return "ISBNFieldControl";
            }         
        }
    }
    
    Protected Overrides ReadOnly Property DefaultTemplateName() As String
        Get
            If Me.ControlMode = SPControlMode.Display Then
                Return Me.DisplayTemplateName
            Else
                Return "ISBNFieldControl"
        End Get
    End Property
    
  8. 添加 DisplayTemplateName 的以下重写。您分配给此属性的 StringRenderingTemplate 对象的 ID,您将在后面的步骤中将该对象添加到以前创建的 ascx 文件中。此对象在"显示"模式中呈现该字段的值。

    public override string DisplayTemplateName
    {
        get
        {
            return "ISBNFieldControlForDisplay";
        }
        set
        {
            base.DisplayTemplateName = value;
        }
    }
    
    Public Overrides Property DisplayTemplateName() As String
        Get
                 Return "ISBNFieldControlForDisplay"
        End Get
        Set
                 MyBase.DisplayTemplateName = Value
        End Set
    End Property
    
  9. 添加 CreateChildControls 方法的以下重写。如果基本 ISBNField 为 null,则该重写不执行任何功能。(如果 ISBNFieldControl 是独立于 ISBNField 的 FieldRenderingControl 属性的 set 取值函数创建的,则它可能为 null,请参阅 ISBN.Field.cs(或 ISBN.Field.vb)中的 FieldRenderingControl 的重写。)

    protected override void CreateChildControls()
    {
        if (this.Field != null)
        {
    
    
        }// end if there is a non-null underlying ISBNField 
    
      // Do nothing if the ISBNField is null.
    }
    
    Protected Overrides Sub CreateChildControls()
        If Me.Field IsNot Nothing Then
    
        End If ' end if there is a non-null underlying ISBNField
    
        ' Do nothing if the ISBNField is null or control mode is Display.
    End Sub
    
  10. 将对基方法的以下调用添加到条件语句的第一行中。此类调用通常是必需的,以确保当继承的子控件是由基 CreateChildControls(而不是由模板)全部或部分呈现时能够创建这些子控件。例如,DefaultTemplates.ascx 中的"TextField"模板(位于 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates 中)呈现子 TextBox,但 CreateChildControls 方法会调整 TextBox 的最大大小,使其符合基本 SPFieldText 字段的最大大小。基 CreateChildControls 还可能创建动态 BaseValidator 控件。但通常情况下,您无权访问基方法的源代码,因此需要进行尝试以确定是否需要调用此基方法,如果需要,则应确定在重写中的调用位置。

    // Make sure inherited child controls are completely rendered.
    base.CreateChildControls();
    
    ' Make sure inherited child controls are completely rendered.
    MyBase.CreateChildControls()
    
  11. 添加下面的行,以将呈现模板中的子控件与在您的自定义字段控件中声明的(或从其父级继承的)子控件字段相关联。在这里,您必须执行该操作,因为对基 CreateChildControls 的调用会将继承的子控件与您的自定义字段类的父级所使用的呈现模板相关联,而不是与自定义呈现模板相关联,因此必须使用新关联替换基础关联。

    // Associate child controls in the .ascx file with the 
    // fields allocated by this control.
    this.ISBNPrefix = (Label)TemplateContainer.FindControl("ISBNPrefix");
    this.textBox = (TextBox)TemplateContainer.FindControl("TextField");
    this.ISBNValueForDisplay = (Label)TemplateContainer.FindControl("ISBNValueForDisplay");
    
    ' Associate child controls in the .ascx file with the 
    ' fields allocated by this control.
    Me.ISBNPrefix = CType(TemplateContainer.FindControl("ISBNPrefix"), Label)
    Me.textBox = CType(TemplateContainer.FindControl("TextField"), TextBox)
    Me.ISBNValueForDisplay = CType(TemplateContainer.FindControl("ISBNValueForDisplay"), Label)
    
  12. 在控件关联代码下添加以下结构。字段在"显示"模式中使用的呈现模板(您在本主题后面步骤中创建的模板)与它在"新建"和"编辑"模式中使用的模板不同;因此,将根据相应模式来初始化不同的子控件。

    if (this.ControlMode != SPControlMode.Display)
    {
    
    }
    else // control mode is Display 
    {                 
    
    }// end control mode is Display
    
    If Not Me.ControlMode = SPControlMode.Display Then
    
    Else ' control mode is display
    
    End If ' end control mode is Display
    
  13. 在上一步中创建的条件结构的"if"(或"If")子句中添加以下内部条件结构。您的代码不应对回发执行任何操作,因为重新初始化回发将取消用户已对子控件的值所做的任何更改。

    if (!this.Page.IsPostBack)
    {
    
    }// end if this is not a postback 
    
    //Do not reinitialize on a postback.
    
    If Not Me.Page.IsPostBack Then
    
    End If ' end if this is not a postback
    
    'Do not reinitialize on a postback.
    
  14. 在最后一步中所添加的条件结构内,添加下面的内部条件,以便在控件模式为"新建"时,使用默认的 ISBN 值初始化 TextBox 子控件。

    if (this.ControlMode == SPControlMode.New)
    {
        textBox.Text = "0-000-00000-0";
    
    } // end assign default value in New mode
    
    If Me.ControlMode = SPControlMode.New Then
       textBox.Text = "0-000-00000-0"
    
    End If ' end assign default value in New mode
    
  15. 在当控件模式为"显示"时运行的 else(或 Else)块中,添加以下代码,以将字段初始化为它在内容数据库中的当前值。

    // Assign current value from database to the label control
    ISBNValueForDisplay.Text = (String)this.ItemFieldValue;
    
    ' Assign current value from database to the label control
    ISBNValueForDisplay.Text = CType(Me.ItemFieldValue, String)
    
  16. 不需要在"编辑"模式下执行任何操作,因为 OnLoad 方法会将 ISBNFieldControl.Value 初始化为 ItemFieldValue 的值,以便在内容数据库中保留该字段的当前值。此时,CreateChildControls 的重写应如下所示。

    protected override void CreateChildControls()
    {
        if (this.Field != null)
        {
            // Make sure inherited child controls are completely rendered.
            base.CreateChildControls();
    
            // Associate child controls in the .ascx file with the 
            // fields allocated by this control.
            this.ISBNPrefix = (Label)TemplateContainer.FindControl("ISBNPrefix");
            this.textBox = (TextBox)TemplateContainer.FindControl("TextField");
            this.ISBNValueForDisplay = (Label)TemplateContainer.FindControl("ISBNValueForDisplay");
    
            if (this.ControlMode != SPControlMode.Display)
            {
                if (!this.Page.IsPostBack)
                {
                    if (this.ControlMode == SPControlMode.New)
                    {
                        textBox.Text = "0-000-00000-0";
    
                    } // end assign default value in New mode
    
                 }// end if this is not a postback 
    
              // Do not reinitialize on a postback.
    
            }// end if control mode is not Display
            else // control mode is Display 
            {                 
                // Assign current value from database to the label control
                ISBNValueForDisplay.Text = (String)this.ItemFieldValue;
    
            }// end control mode is Display
    
        }// end if there is a non-null underlying ISBNField 
    
        // Do nothing if the ISBNField is null.
    }
    
    Protected Overrides Sub CreateChildControls()
        If Me.Field IsNot Then
            ' Make sure inherited child controls are completely rendered.
            MyBase.CreateChildControls()
    
            ' Associate child controls in the .ascx file with the 
            ' fields allocated by this control.
            Me.ISBNPrefix = CType(TemplateContainer.FindControl("ISBNPrefix"), Label)
            Me.textBox = CType(TemplateContainer.FindControl("TextField"), TextBox)
            Me.ISBNValueForDisplay = CType(TemplateContainer.FindControl("ISBNValueForDisplay"), Label)
    
            If Not Me.ControlMode = SPControlMode.Display Then
    
                 If Not Me.Page.IsPostBack Then
                     If Me.ControlMode = SPControlMode.New Then
                         textBox.Text = "0-000-00000-0"
    
                     End If ' end assign default value in New mode
    
                 End If ' end if this is not a postback
    
                 'Do not reinitialize on a postback.
    
            Else ' control mode is display
                ' Assign current value from database to the label control
                ISBNValueForDisplay.Text = CType(Me.ItemFieldValue, String)
    
            End If ' end control mode is Display
    
        End If ' end if there is a non-null underlying ISBNField
    
        ' Do nothing if the ISBNField is null or control mode is Display.
    End Sub
    
  17. 添加 Value 属性的以下重写,该属性是用户界面中的 字段的值。如果最终用户已更改此值,但尚未保存,则 Value 属性不一定是基本 ISBNField(从 SPFieldText 派生)对象的实际值或内容数据库中的字段的值。注意,get 取值函数和 set 取值函数都从调用 EnsureChildControls(将在需要时调用 CreateChildControls)开始。调用 EnsureChildControls 是必需的,除非 (1) 您先调用基属性,(2) 您知道该基属性的 set 和 get 取值函数会调用 EnsureChildControls。如果将从 TextField 继承的基础 TextBox 子控件替换为完全不同类型的控件(如下拉列表框),则 Value 的重写的 set 取值函数和 get 取值函数将需要直接设置此控件,而不是调用基属性。要确保控件最初加载基础 ISBNField 对象中的值,OnLoad() 方法应将 ISBNFieldControl.Value 设置为 ItemFieldValue 的值,该值 基础 ISBNField 对象的值。

    public override object Value
    {
        get
        {
            EnsureChildControls();
            return base.Value;
        }
        set
        {
             EnsureChildControls();
             base.Value = (String)value;
             // The value of the ISBNPrefix field is hardcoded in the
             // template, so it is not set here.
        }
    }
    
    Public Overrides Property Value() As Object
        Get
            EnsureChildControls()
            Return MyBase.Value
        End Get
        Set(ByVal value As Object)
            EnsureChildControls()
            MyBase.Value = CType(value, String)
            ' The value of the ISBNPrefix field is hardcoded in the
            ' template, so it is not set here.
        End Set
    End Property
    

创建字段呈现模板

创建呈现模板

  1. 打开 ISBNFieldControl.ascx 文件。

  2. 该文件中已包含下列指令。

    <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
    <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
    <%@ Import Namespace="Microsoft.SharePoint" %> 
    <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
    
  3. 此标记下面是 <%@ Control 指令,该指令引用您在前面的步骤中删除的文件,并且包含此项目中不使用的其他属性。将其替换为以下简化的指令。

    <%@ Control Language="C#" %>
    
  4. 在这些指令下,添加以下标记。

    <SharePoint:RenderingTemplate ID="ISBNFieldControl" runat="server">
      <Template>
        <asp:Label ID="ISBNPrefix" Text="ISBN" runat="server" />
        &nbsp;
        <asp:TextBox ID="TextField" runat="server"  />
      </Template>
    </SharePoint:RenderingTemplate>
    

    请注意有关此标记的以下事实:

    • RenderingTemplate 的 ID 必须与用于 DefaultTemplateName 属性重写的字符串相同。

    • 模板中 Label 控件的 Text 属性是在此处设置的,因为它不会发生任何变化。

    • 两个控件之间有一个 HTML"&nbsp;"元素。

    • TextBox 定义与 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx 中定义的"TextField"RenderingTemplate 中的定义相同。但此处必须重复该定义,因为 DefaultTemplateName 的重写指向此自定义模板,而不是"TextField"模板。自定义模板中将使用相同的 ID,因为基 CreateChildControls 方法(请参阅上文)可能通过此 ID 引用该控件。

  5. 将以下额外 RenderingTemplate 添加到第一个模板正下方。

    <SharePoint:RenderingTemplate ID="ISBNFieldControlForDisplay" runat="server">
      <Template>
        <asp:Label ID="ISBNValueForDisplay" runat="server" />
      </Template>
    </SharePoint:RenderingTemplate>
    

    CreateChildControls 方法会在"显示"模式下将此 RenderingTemplate 指定为默认模板。

创建字段类型定义

创建字段类型定义

  1. 在 Visual Studio 中,生成该项目。该项目尚未完成,但此时您需要为程序集生成 GUID 和公钥标记。

  2. 打开 fldtypes_ISBNField.xml 文件,并将其内容替换为以下标记。

    <?xml version="1.0" encoding="utf-8" ?>
    <FieldTypes>
      <FieldType>
        <Field Name="TypeName">ISBN</Field>
        <Field Name="ParentType">Text</Field>
        <Field Name="TypeDisplayName">ISBN</Field>
        <Field Name="TypeShortDescription">ISBN for a book</Field>
        <Field Name="UserCreatable">TRUE</Field>
        <Field Name="ShowOnListCreate">TRUE</Field>
        <Field Name="ShowOnSurveyCreate">TRUE</Field>
        <Field Name="ShowOnDocumentLibraryCreate">TRUE</Field>
        <Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
        <Field Name="FieldTypeClass">Contoso.SharePoint.ISBNField, $SharePoint.Project.AssemblyFullName$</Field>
      </FieldType>
    </FieldTypes>
    

    该文件定义 SharePoint Foundation 的自定义字段类型。有关它的元素的用途和含义的详细信息,请参阅如何:创建自定义字段类型定义了解 FldTypes.xml 文件FieldTypes 元素(字段类型)FieldType 元素(字段类型)Field 元素(字段类型)。请注意,<Field Name="FieldTypeClass"> 元素必须全部在一行上。

  3. <Field Name="FieldTypeClass"> 元素的值是您的自定义字段类的完全限定名称,后跟逗号和 Visual Studio 2010 标记 ($SharePoint.Project.AssemblyFullName$)。编译该项目时,会创建此文件的副本,在该副本中,该标记将被替换为程序集的 4 个部分组成的完整名称。从 Visual Studio 2010 的 Visual Studio"生成"菜单中选择"部署解决方案"时,会部署该副本。如果您使用的不是 Visual Studio 2010,则此时需要编译该项目(即使它尚未完成),以生成公钥标记。然后可使用如何:创建用于获取程序集全名的工具中介绍的工具获取 4 个部分组成的完整名称,并手动将其粘贴到副本中,以替换该标记。

创建 XSLT 样式表

创建 XSLT 样式表

  • 打开 fldtypes_ISBNField.xsl 文件,并将 <?xml version="1.0" encoding="utf-8"?> 标记下方的全部内容替换为以下标记。

    <xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
                    xmlns:d="https://schemas.microsoft.com/sharepoint/dsp"
                    version="1.0"
                    exclude-result-prefixes="xsl msxsl ddwrt"
                    xmlns:ddwrt="https://schemas.microsoft.com/WebParts/v2/DataView/runtime"
                    xmlns:asp="https://schemas.microsoft.com/ASPNET/20"
                    xmlns:__designer="https://schemas.microsoft.com/WebParts/v2/DataView/designer" 
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                    xmlns:SharePoint="Microsoft.SharePoint.WebControls"
                    xmlns:ddwrt2="urn:frontpage:internal">
    
      <xsl:template match="FieldRef[@Name = 'ISBN']" mode="Text_body">
    
        <xsl:param name="thisNode" select="." /> 
    
        <span style="background-color:lightgreen;font-weight:bold">
    
          <xsl:value-of select="$thisNode/@*[name()=current()/@Name]" />
    
        </span>
    
      </xsl:template >
    
    </xsl:stylesheet>
    

    XSLT 样式表在列表视图上呈现字段。列表视图的 ISBN 列中的单元格有淡绿色的背景,其中 ISBN 值以粗体显示。

    列表视图模式中的列标题由 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATES\LAYOUTS\XSL 中内置文件 fldtypes.xsl 中提供的其他 XSLT 样式表呈现。

生成和测试自定义字段类型

生成和测试自定义字段类型

  1. 在"生成"菜单上选择"部署"。这将自动重新生成程序集,将该程序集部署到 GAC,将 ascx 文件部署到 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates,将 fldtypes*.xml 文件部署到 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\XML,将 fldtypes*.xsl 文件部署到 %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\LAYOUTS\XSL,并回收 Web 应用程序。

    备注

    如果部署环境为包含多台服务器的服务器场,则不会自动执行部署步骤。从管理中心应用程序的"解决方案管理"页或使用 SharePoint Management Shell cmdlet 部署解决方案 isbn_field_type.wsp。

  2. 在您的 SharePoint Web 应用程序中打开一个网站并创建一个名为"Books"的列表。

  3. 将一个新列添加到该列表中。在"创建列"页上,输入"ISBN"作为列名称。

  4. 单击"ISBN for a book"单选按钮。

  5. 单击"是"单选按钮,创建所需字段。

  6. 保留"添加到默认视图"复选框为启用状态。

  7. 单击"确定"。

  8. 向该列表添加项。

  9. 在"新项目"页上,验证该字段最初是否设置为默认值"0-000-00000-0",除字段标题"ISBN"外,该值本身还紧跟在"ISBN"之后,如"新建"和"编辑"模式的呈现模板中的定义。

  10. 输入无效的 ISBN 值,以查看在尝试保存该项目时所遇到的各种错误。

  11. 查看如果将该字段完全留空将会发生什么情况。

  12. 最后,输入 0-262-61108-2 或您知道有效的其他值,然后单击"保存"。(如果收到有效 ISBN 的相关错误,请确保该值的末尾没有空格)。

  13. 确保列表视图上的值为粗体,并具有淡绿色背景。

  14. 单击项目标题以打开"显示"页。确认该字段以内容数据库中的当前值呈现。注意,尽管存在字段标题"ISBN",但该值本身在处于"编辑"和"新建"模式时并不紧跟在"ISBN"之后,因为此前缀不是"显示"模式的呈现模板的一部分。

  15. 单击"编辑项目"编辑该字段。确认该字段最初是否设置为其当前值,而非默认值,除字段标题"ISBN"外,该值本身还紧跟在"ISBN"之后,如"新建"和"编辑"模式的呈现模板中的定义。

  16. 将字段值更改为无效,并确保在编辑模式下出现验证错误,就像在新建模式下一样。

移动设备上的字段呈现与计算机上的字段呈现有何区别

在 SharePoint Foundation 中,移动设备与计算机在使用自定义字段呈现控件呈现字段方面类似。但应记住以下区别:

  • 移动设备页是一组与 SharePoint Foundation 网站的主页面(设计用于计算机浏览器)完全不同的页面,它们引用一组不同的 RenderingTemplate 对象。

  • 移动 RenderingTemplate 对象在 MobileDefaultTemplates.ascx 和 GbwMobileDefaultTemplates.ascx(而不是 DefaultTemplates.ascx)中声明。

  • 移动字段呈现控件具有自己的命名空间 Microsoft.SharePoint.MobileControls,并且它们从 ASP.NET System.Web.UI.MobileControls 命名空间(而不是 System.Web.UI.WebControls 命名空间)中的类派生。

  • 移动字段呈现控件的继承层次结构与常规字段呈现控件稍有不同。例如,常规字段呈现中 TemplateBasedControlFormComponent 的函数合并到 SPMobileComponent 类中。

  • 与为计算机浏览器创建的自定义字段呈现控件相比,为移动上下文创建的自定义字段呈现控件更多地依赖控件的 CreateChildControls 方法来呈现字段,而相应地较少依赖呈现模板。此外,在开发自定义移动呈现控件时,不需要经常重写 CreateChildControls 方法本身。相反,您的自定义移动呈现控件通常会重写 CreateChildControls 方法所调用的以下四种方法中的一种或几种:

请参阅

引用

FieldTypes 元素(字段类型)

FieldType 元素(字段类型)

Field 元素(字段类型)

Namespace Naming Guidelines

RenderPattern 元素(字段类型)

AlternateTemplateName

BaseValidator

ControlTemplate

CreateChildControls

DefaultAlternateTemplateName

DefaultTemplateName

EnsureChildControls

FieldRenderingControl

GetValidatedString

ItemFieldValue

Label

OnLoad()

RegularExpressions

RenderingTemplate

SPControlMode

SPFieldText

SPFieldValidationException

Template

TemplateName

TextBox

TextField

ValidationRule

Value

概念

如何:创建自定义字段类

如何:创建自定义字段类型定义

自定义字段类型部署

自定义字段数据验证

如何:创建字段呈现控件

如何:创建字段呈现模板

如何:创建自定义字段类型

解决方案概述