Partager via


Procédure pas à pas : création d'un type de champ personnalisé

Dernière modification : vendredi 25 juin 2010

S’applique à : SharePoint Foundation 2010

Dans cet article
Configuration du projet
Création de la classe de règle de validation
Création de la classe de champ personnalisé
Création du contrôle de rendu de champ
Création du modèle de rendu de champ
Création de la définition de type de champ
Création de la feuille de style XSLT
Générer et tester le type de champ personnalisé
Différences de rendu des champs entre les périphériques mobiles et les ordinateurs

Cette rubrique vous guide pas à pas dans la création d’un type de champ personnalisé. Vous allez créer un champ destiné à contenir un numéro ISBN (International Standard Book Number) de 10 chiffres.

Pour une présentation des étapes impliquées dans la création d’un type de champ personnalisé et dans la définition de son affichage, voir Procédure : créer un type de champ personnalisé.

Conditions requises

Microsoft Visual Studio 2010

Configuration du projet

Pour configurer le projet de champ personnalisé

  1. Dans Visual Studio, créez un Projet SharePoint vide. Définissez-le en tant que solution de batterie, et non comme solution en bac à sable (sandboxed) ; puis, nommez-le ISBN_Field_Type.

  2. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet et sélectionnez Propriétés.

  3. Sous l’ongletApplication de la boîte de dialogue Propriétés, entrez Contoso.SharePoint.ISBN_Field_Type comme Nom d’assembly et Contoso.SharePoint comme Espace de noms par défaut. Laissez Version cible avec la valeur .NET Framework 3.5.

  4. Si la zone Plateformes Solution du Menu standardVisual Studio ne mentionne pas « Any CPU » ou « x64 », ouvrez l’onglet Créer et définissez la Plateforme cible avec la valeur « Any CPU » ou « x64 ». Pour plus d’informations sur le choix proposé, voir Procédure : définir le Framework et l’unité centrale cibles adéquats.

  5. Cliquez sur le bouton Enregistrer tout de la barre d’outils.

  6. Cliquez avec le bouton droit sur le nom du projet dans l’Explorateur de solutions, puis sélectionnez Ajouter, Nouvel élément.

  7. Dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez Visual C#, Code (ou Visual Basic, Code) dans l’arborescence Modèles installés.

  8. Sélectionnez Classe dans la zone Modèles, puis entrez ISBN.Field.cs (ou ISBN.Field.vb) dans la zone Nom. Cliquez sur Ajouter.

  9. Répétez l’étape précédente pour créer la deuxième classe, mais entrez ISBN.FieldControl.cs (ou ISBN.FieldControl.vb) dans la zone Nom. Cliquez sur Ajouter.

  10. Ajoutez une troisième classe de la même façon et entrez ISBN10ValidationRule.cs (ou ISBN10ValidationRule.vb) dans la zone Nom. Cliquez sur Ajouter.

  11. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet et sélectionnez Ajouter, puis Dossier mappé SharePoint.

  12. Utilisez le contrôle d’arborescence qui s’affiche pour mapper le dossier avec TEMPLATE\ControlTemplates, puis cliquez sur OK.

  13. Cliquez avec le bouton droit sur le nouveau dossier ControlTemplates (pas sur le nom du projet) dans l’Explorateur de solutions, puis sélectionnez Ajouter, Nouvel élément.

  14. Dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez SharePoint, 2010 dans l’arborescence Modèles installés.

  15. Sélectionnez un Contrôle utilisateur SharePoint dans la zone Modèles et attribuez au fichier ascx le nom ISBNFieldControl.ascx. Cliquez sur Ajouter. Visual Studio ajoute automatiquement le fichier au manifeste de la solution SharePoint Solution et définit son déploiement sur %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates. Il ajoute également l’assembly au manifeste et définit son déploiement sur le Global Assembly Cache (GAC).

    ConseilConseil

    N’ajoutez pas le Contrôle utilisateur en cliquant avec le bouton droit sur le nom du projet dans l’Explorateur de solutions. Quand un Contrôle utilisateur est ajouté de cette façon, Visual Studio le place dans un sous-dossier de TEMPLATE\ControlTemplates et, s’il n’est pas déplacé, Visual Studio le déploiera dans un sous-dossier correspondant de %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates. Les modèles de rendu des sous-dossiers ne sont pas chargés.

  16. Supprimez les fichiers ISBNFieldControl.ascx.cs et ISBNFieldControl.ascx.designer.cs (ou les fichiers ISBNFieldControl.ascx.vb et ISBNFieldControl.ascx.designer.vb) qui sont créés automatiquement sous le fichier ISBNFieldControl.ascx. Ils ne sont pas nécessaires pour ce projet. Le contenu par défaut de ISBNFieldControl.ascx se rapporte au fichier ISBNFieldControl.ascx.cs (ou ISBNFieldControl.ascx.vb) que vous venez de supprimer et, si vous générez le projet à ce stade, le compilateur affiche un avertissement relatif au fichier manquant. Ignorez l’avertissement : le contenu par défaut est modifié dans une étape ultérieure du présent article.

  17. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet, sélectionnez Ajouter, puis Dossier mappé SharePoint.

  18. Utilisez le contrôle d’arborescence qui s’affiche pour mapper le dossier avec TEMPLATE\XML, puis cliquez sur OK.

  19. Cliquez avec le bouton droit sur le nouveau dossier XML (pas sur le nom du projet) dans l’Explorateur de solutions, puis sélectionnez Ajouter, Nouvel élément.

  20. Dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez Visual C#, Données (ou Visual Basic, Données), puis Fichier XML dans la fenêtre Modèles.

  21. Dans la zone Nom, tapez fldtypes_ISBNField.xml et cliquez sur Ajouter.

  22. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet, sélectionnez Ajouter, puis Dossier mappé SharePoint.

  23. Utilisez le contrôle d’arborescence qui s’affiche pour mapper le dossier avec TEMPLATE\LAYOUTS\XSL, puis cliquez sur OK.

  24. Cliquez avec le bouton droit sur le nouveau dossier XSL (pas sur le nom du projet) dans l’Explorateur de solutions, puis sélectionnez Ajouter, Nouvel élément.

  25. Dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez Visual C#, Données (ou Visual Basic, Données), puis Fichier XSLT dans la fenêtre Modèles.

  26. Dans la zone Nom, tapez fldtypes_ISBNField.xsl et cliquez sur Ajouter. Notez que le nom est très similaire à celui du précédent fichier que vous avez créé. Les deux fichiers ont des objectifs différents et sont déployés dans des dossiers distincts. Conservez-les tels quels tandis que vous étudiez le présent article.

  27. Cliquez avec le bouton droit sur le nœud Références de l’Explorateur de solutions, cliquez sur Ajouter une référence, puis sélectionnez PresentationFramework.dll sous l’onglet .NET de la boîte de dialogue Ajouter une référence. Cliquez sur OK. (Cet assembly contient la définition de la classe ValidationRule que vous créerez dans la prochaine procédure.)

Création de la classe de règle de validation

Pour créer une classe de règle de validation

  1. Ouvrez le fichier ISBN10ValidationRule.cs (ou ISBN10ValidationRule.vb) et ajoutez les instructions suivantes.

    using System.Text.RegularExpressions;
    using System.Windows.Controls;
    using System.Globalization;
    
    Imports System.Text.RegularExpressions
    Imports System.Windows.Controls
    Imports System.Globalization
    
  2. Modifiez l’espace de noms afin de respecter les instructions définies dans les Conventions de dénomination des espaces de noms (éventuellement en anglais). Dans cette procédure, utilisez Contoso.System.Windows.Controls.

  3. Remplacez la déclaration de classe par le code suivant :

    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
    

    La classe de règle de validation que vous venez de créer contient toute la logique de validation détaillée. Pour plus d'informations sur les classes de règle de validation, voir System.Text.RegularExpressions et ValidationRule.

Création de la classe de champ personnalisé

Pour créer une classe de champ personnalisé

  1. Ouvrez le fichier ISBN.Field.cs (ou ISBN.Field.vb).

  2. Ajoutez les instructions suivantes.

    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. Ajoutez les instructions suivantes. Celles-ci permettent à l’implémentation de votre classe de référencer les autres classes que vous créerez dans les étapes ultérieures. Jusqu’à ce que ces classes soient créées, il se peut que le compilateur affiche des avertissements relatifs à ces instructions.

    using Contoso.SharePoint.WebControls;
    using Contoso.System.Windows.Controls;
    
    Imports Contoso.SharePoint.WebControls
    Imports Contoso.System.Windows.Controls
    
  4. Vérifiez que l’espace de noms est bien Contoso.SharePoint.

  5. Assurez-vous que la classe se nomme ISBNField et modifiez sa déclaration afin qu’elle hérite de SPFieldText.

    public class ISBNField : SPFieldText
    {
    }
    
    Public Class ISBNField
        Inherits SPFieldText
    
    End Class
    
  6. Ajoutez les constructeurs obligatoires suivants pour la classe.

    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. Ajoutez la substitution suivante de la propriété FieldRenderingControl à la classe. ISBNFieldControl est une classe que vous créerez dans une étape ultérieure.

    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. Ajoutez la substitution suivante de la méthode GetValidatedString à la classe 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
    

    Cette substitution illustre un modèle commun pour les substitutions de GetValidatedString :

    • Les substitutions de la méthode GetValidatedString vérifient si le champ est obligatoire et, le cas échéant, la méthode substituée lève un exception SPFieldValidationException lorsque la valeur est null ou une String vide. Cette exception est interceptée par les pages Nouvel élément et Modifier l'élément si l'utilisateur essaie d'enregistrer l'élément de liste en cours de création ou de modification. Dans ce cas, la page reste ouverte et la propriété Message() de l'exception entraîne l'apparition d'un message d'erreur sous le champ vide.

    • Les substitutions de GetValidatedString lèvent une SPFieldValidationException lorsque la valeur n'est pas valide, entraînant l'apparition d'un message d'erreur sous le champ non valide.

    • Les substitutions de GetValidatedString appellent ensuite le GetValidatedString de base, si la valeur passe la validation personnalisée.

  9. Enregistrez et fermez le fichier.

Création du contrôle de rendu de champ

Pour créer le contrôle de rendu de champ

  1. Ouvrez le fichier ISBN.FieldControl.cs (ou ISBN.FieldControl.vb).

  2. Ajoutez les instructions suivantes.

    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. Modifiez l’espace de noms en Contoso.SharePoint.WebControls.

  4. Vérifiez que la classe se nomme ISBNFieldControl et modifiez sa déclaration pour spécifier qu’elle hérite de TextField.

    public class ISBNFieldControl : TextField
    {
    }
    
    Public Class ISBNFieldControl 
        Inherits TextField
    
    End Class
    
  5. Ajoutez un champ protégé pour un contrôle Web Label ASP.NET qui ajoutera le préfixe ISBN devant chaque numéro ISBN qui est rendu en mode Création ou Édition. Il n’est pas nécessaire d’ajouter un champ TextBox protégé pour le numéro ISBN lui-même, car le contrôle ISBNFieldControl personnalisé hérite le champ de TextField.

    protected Label ISBNPrefix;
    
    Protected Label ISBNPrefix
    
  6. Ajoutez un autre champ protégé pour un contrôle Web Label ASP.NET qui restituera la valeur courante du champ en mode Affichage.

    protected Label ISBNValueForDisplay;
    
    Protected Label ISBNValueForDisplay
    
  7. Puis, ajoutez la substitution suivante de la propriété DefaultTemplateName. La valeur String que vous attribuez à cette propriété est l’ID d’un objet RenderingTemplate que vous ajouterez, dans une étape ultérieure, au fichier .ascx que vous avez créé précédemment. (Lorsque votre projet est terminé, ce fichier est déployé sur le dossier %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\CONTROLTEMPLATES.) Si aucune des propriétés ControlTemplate, Template ou TemplateName n’est substituée, RenderingTemplate sera appelé de la façon suivante : ControlTemplate renverra Template, qui, à son tour, renverra la propriété Template de quelque objet RenderingTemplate que ce soit nommé par TemplateName. Enfin, l’accesseur get de TemplateName renverra DefaultTemplateName. Dans un cas plus complexe où, par exemple, vous disposez de modèles distincts pour les modes Création et Édition, vous devrez substituer une ou plusieurs des précédentes propriétés, ainsi que, probablement, les propriétés AlternateTemplateName ou DefaultAlternateTemplateName.

    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. Ajoutez la substitution suivante de DisplayTemplateName. La valeur String que vous attribuez à cette propriété est l’ID d’un objet RenderingTemplate que vous ajouterez, dans une étape ultérieure, au fichier ascx que vous avez créé précédemment. Cet objet restitue la valeur du champ en mode Affichage.

    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. Ajoutez la substitution suivante de la méthode CreateChildControls. La substitution n’effectue aucune fonction si le ISBNField sous-jacent est null. (Il peut être null si le ISBNFieldControl est créé indépendamment de l’accesseur set de la propriété FieldRenderingControl de ISBNField – voir la substitution de FieldRenderingControl dans ISBN.Field.cs [ou ISBN.Field.vb].)

    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. Ajoutez l’appel suivant à la méthode de base en tant que première ligne de la structure conditionnelle. Un appel de ce type est généralement nécessaire pour garantir que les contrôles enfants hérités sont créés dans le cas où ils sont restitués entièrement ou partiellement par les CreateChildControls de base, au lieu de l’être par un modèle. Par exemple, le modèle « TextField » de DefaultTemplates.ascx (dans %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates) restitue l’objet TextBox enfant, mais la méthode CreateChildControls ajuste la taille maximale de TextBox sur la taille maximale du champ SPFieldText sous-jacent. Les CreateChildControls de base peuvent également créer des contrôles BaseValidator dynamiques. Toutefois, en règle générale, vous n’avez pas accès au code source de la méthode de base, et c’est donc par expérimentation que vous devez déterminer s’il doit être appelé et, le cas échéant, où il doit être appelé dans votre substitution.

    // Make sure inherited child controls are completely rendered.
    base.CreateChildControls();
    
    ' Make sure inherited child controls are completely rendered.
    MyBase.CreateChildControls()
    
  11. Ajoutez les lignes ci-après pour associer les contrôles enfants des modèles de rendu aux champs de contrôle enfants déclarés dans votre contrôle de champ personnalisé (ou hérités de son parent). Vous devez le faire maintenant, car l’appel aux CreateChildControls de base associera les contrôles enfants hérités aux modèles de rendu utilisés par le parent de la classe du champ personnalisé, pas aux modèles de rendu personnalisé, ce qui signifie que l’association de base doit être remplacée par une nouvelle.

    // 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. Ajoutez la structure ci-après sous le code d’association du contrôle. Votre champ utilise un modèle de rendu différent (que vous créerez dans une étape ultérieure du présent article) en mode Affichage de celui utilisé dans les modes Création et Édition ; en conséquence, différents contrôles enfants sont initialisés en fonction du mode.

    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. Ajoutez la structure conditionnelle interne suivante à l’intérieur de la clause « if » (ou « If ») de la structure conditionnelle créée à l’étape précédente. Le code ne doit en rien agir sur une publication, car la réinitialisation sur une publication annulerait toutes les modifications qu’un utilisateur apporterait aux valeurs des contrôles enfants.

    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. Dans la structure conditionnelle que vous avez ajoutée à l'étape précédente, ajoutez le conditionnel interne suivant pour initialiser le contrôle enfant TextBox avec une valeur ISBN par défaut lorsque le mode de contrôle est New (Création).

    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. Dans le bloc else (ou Else) qui s’exécute quand le contrôle est en mode Affichage, ajoutez le code suivant pour initialiser le champ à sa valeur courante à partir de la base de données de contenu.

    // 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. Rien ne doit être fait en mode Édition, car la méthode OnLoad initialisera ISBNFieldControl.Value à la valeur de ItemFieldValue qui contient la valeur actuelle du champ dans la base de données de contenu. À ce stade, votre substitution de CreateChildControls doit ressembler à ce qui suit.

    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. Ajoutez la substitution suivante de la propriété Value, qui est la valeur du champ dans l’interface utilisateur. Si l’utilisateur final a modifié la valeur sans l’avoir enregistrée, alors la propriété Value n’est pas nécessairement la valeur réelle de l’objet ISBNField sous-jacent (dérivé de SPFieldText) ou de la valeur du champ dans la base de données de contenu. Notez que les accesseurs get et set commencent par appeler EnsureChildControls (qui appellera CreateChildControls si nécessaire). L’appel des EnsureChildControls est obligatoire sauf si (1) vous appelez d’abord la propriété de base et (2) vous savez que les accesseurs set et get de la propriété de base appellent EnsureChildControls. Si vous remplaciez le contrôle enfant TextBox sous-jacent hérité de TextField par un type de contrôle entièrement différent, tel qu’une zone de liste déroulante, alors les accesseurs set et get de votre substitution de la propriété Value devraient définir ce contrôle directement plutôt que d’appeler une propriété de base. Pour s’assurer que le contrôle se charge initialement avec la valeur de l’objet ISBNField sous-jacent, la méthode OnLoad() définit ISBNFieldControl.Value avec la valeur ItemFieldValue qui est la valeur de l’objet ISBNField sous-jacent.

    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
    

Création du modèle de rendu de champ

Pour créer les modèles de rendu

  1. Ouvrez le fichier ISBNFieldControl.ascx.

  2. Les directives suivantes se trouvent déjà dans le fichier.

    <%@ 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. Sous ce balisage figure une directive <%@ Control qui fait référence aux fichiers que vous avez supprimés dans une étape antérieure et qui contient d’autres attributs qui ne sont pas utilisés dans ce projet. Remplacez-la par la directive suivante simplifiée.

    <%@ Control Language="C#" %>
    
  4. Sous les directives, ajoutez le balisage ci-après.

    <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>
    

    Notez les faits suivants à propos de ce balisage :

    • L’ID du RenderingTemplate doit être identique à la chaîne que vous avez utilisée dans votre substitution de la propriété DefaultTemplateName.

    • L'attribut Text du contrôle Label est défini ici dans le modèle, car il ne change jamais.

    • Un élément "&nbsp;" HTML s'insère entre deux contrôles.

    • La définition de TextBox est identique à celle du RenderingTemplate « TextField » spécifiée dans %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx. Cependant, la définition doit être répétée ici, car votre substitution de DefaultTemplateName pointe vers ce modèle personnalisé, et non vers le modèle « TextField ». Le même ID est utilisé dans le modèle personnalisé, car la méthode CreateChildControls de base (voir ci-dessus) peut faire référence au contrôle par l’intermédiaire de cet ID.

  5. Ajoutez le RenderingTemplate supplémentaire suivant juste sous le premier.

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

    Ce RenderingTemplate sera défini comme modèle par défaut en mode d’affichage par la méthode CreateChildControls.

Création de la définition de type de champ

Pour créer la définition de type de champ

  1. Dans Visual Studio, générez le projet. Le projet n’est pas terminé, mais vous devez le générer à ce stade pour créer un GUID et un jeton de clé publique pour l’assembly.

  2. Ouvrez le fichier fldtypes_ISBNField.xml et remplacez son contenu par le balisage suivant.

    <?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>
    

    Ce fichier définit le type de champ personnalisé pour SharePoint Foundation. Pour plus d’informations sur la fonction et la signification de ses éléments, voir Procédure : créer une définition de type de champ personnalisé, Présentation du fichier FldTypes.xml, FieldTypes, élément (Types de champs), FieldType, élément (types de champ) et Field, élément (types de champs). Notez que l’élément <Field Name="FieldTypeClass"> doit tenir entièrement sur une seule ligne.

  3. La valeur de l’élément <Field Name="FieldTypeClass"> est le nom entièrement qualifié de la classe de votre champ personnalisé, suivi d’une virgule et d’un jeton Visual Studio 2010 ($SharePoint.Project.AssemblyFullName$). Lorsque vous compilez le projet, une copie de ce fichier est créée, dans laquelle le jeton est remplacé par le nom complet en quatre parties de l’assembly. C’est cette copie qui est déployée lorsque vous sélectionnez Déployer la solution dans le menu Visual Studio Générer de Visual Studio 2010. Si vous n’utilisez pas Visual Studio 2010, vous devrez compiler le projet à ce stade, même s’il n’est pas terminé, afin de générer un jeton de clé publique. Vous pouvez alors utiliser l’outil décrit dans Procédure : créer un outil pour obtenir le nom complet d'un assembly pour obtenir le nom complet en quatre parties et le coller manuellement à la place du jeton.

Création de la feuille de style XSLT

Pour créer la feuille de style XSLT

  • Ouvrez le fichier fldtypes_ISBNField.xsl et remplacez le balisage situé sous la balise <?xml version="1.0" encoding="utf-8"?> par celui ci-après.

    <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>
    

    La feuille de style XSLT restitue le champ sur les affichages de liste. Les cellules de la colonne ISBN des affichages de liste ont un arrière-plan vert clair, la valeur ISBN étant affichée en gras.

    L’en-tête de colonne du mode d’affichage de liste est restitué par une autre feuille de style XSLT, fournie dans le fichier intégré fldtypes.xsl de %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATES\LAYOUTS\XSL.

Générer et tester le type de champ personnalisé

Pour générer et tester le type de champ personnalisé

  1. Sélectionnez Déployer dans le menu générer. Cette option régénère automatiquement l’assembly, le déploie sur le GAC, déploie le fichier ascx sur %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\ControlTemplates, déploie le fichierfldtypes*.xml sur %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\XML, déploie le fichier fldtypes*.xsl sur %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\LAYOUTS\XSL, et recycle l’application Web.

    Notes

    Si votre environnement de développement est une batterie multiserveur, l’étape de déploiement ne se produit pas automatiquement. Déployez la solution, isbn_field_type.wsp, depuis la page Gestion des solutions de l’application Administration centrale ou avec une applet de commande SharePoint Management Shell.

  2. Ouvrez un site Web dans votre application Web SharePoint et créez une liste intitulée Livres.

  3. Ajouter une nouvelle colonne à la liste. Dans la page Créer une colonne, entrez « ISBN » comme nom de colonne.

  4. Cliquez sur la case d'option ISBN pour un livre.

  5. Cliquez sur la case d'option Oui pour rendre le champ obligatoire.

  6. Laissez la case à cocher Ajouter à l'affichage par défaut activée.

  7. Cliquez sur OK.

  8. Ajoutez un élément à la liste.

  9. Sur la page Nouvel élément, vérifiez que le champ est initialement défini avec la valeur par défaut « 0-000-00000-0 » et que, en plus du titre de champ « ISBN », la valeur elle-même est aussi immédiatement précédée par « ISBN » comme défini dans le modèle de rendu des modes Création et Édition.

  10. Entrez des valeurs ISBN non valides pour vérifier quels types d'erreurs vous obtenez lorsque vous essayez d'enregistrer l'élément.

  11. Vérifiez ce qui se passe si vous laissez le champ entièrement vide.

  12. Enfin, entrez 0-262-61108-2 ou une autre valeur que vous savez valide et cliquez sur Enregistrer. (Si vous obtenez des erreurs indiquant un ISBN non valide, vérifiez que vous n’avez pas laissé d’espace vide à la fin de la valeur.)

  13. Vérifiez que la valeur dans l’affichage de liste est en caractères gras sur fond de couleur vert clair.

  14. Cliquez sur le titre de l’élément pour ouvrir la page d’affichage. Confirmez que le champ apparaît avec sa valeur actuelle dans la base de données de contenu. Notez que même si le titre de champ « ISBN » est présent, la valeur elle-même n’est pas immédiatement précédée de « ISBN » comme cela est le cas dans les modes Édition et Création, car ce préfixe n’appartenait pas au modèle de rendu du mode d’affichage.

  15. Cliquez sur Modifier l’élément pour modifier le champ. Confirmez que le champ est initialement défini avec sa valeur courante, pas avec la valeur par défaut, et qu’en plus du titre de champ « ISBN », la valeur elle-même est aussi immédiatement précédée par « ISBN », tel que défini dans le modèle de rendu des modes Édition et Création.

  16. Modifiez le champ en y indiquant des valeurs non valides et vérifiez que des erreurs de validation apparaissent en mode Édition exactement comme en mode Création.

Différences de rendu des champs entre les périphériques mobiles et les ordinateurs

Dans SharePoint Foundation, le rendu de champ avec contrôles de rendu de champ personnalisé pour les périphériques mobiles est similaire au rendu de champ avec contrôles de rendu de champ personnalisé pour les ordinateurs. Mais gardez ces différences présentes à l’esprit :

  • Les pages mobiles constituent un ensemble de pages totalement distinct des pages principales d'un site SharePoint Foundation (qui sont conçues pour les navigateurs d'ordinateur) et font référence à un ensemble différent d'objets RenderingTemplate.

  • Les objets RenderingTemplate mobiles sont déclarés dans MobileDefaultTemplates.ascx et GbwMobileDefaultTemplates.ascx, pas dans DefaultTemplates.ascx.

  • Les contrôles de rendu de champ mobiles possèdent leur propre espace de noms, Microsoft.SharePoint.MobileControls et dérivent de classes de l'espace de noms System.Web.UI.MobileControls ASP.NET (plutôt que de l'espace de noms System.Web.UI.WebControls).

  • Pour les contrôles de rendu de champ mobiles, la hiérarchie d'héritage est un peu différente de celle des contrôles de rendu de champ normaux. Par exemple, les fonctions de TemplateBasedControl et de FormComponent dans le rendu de champ normal sont combinées dans la classe SPMobileComponent.

  • Les contrôles de rendu de champ personnalisés que vous créez pour des contextes mobiles reposent plus sur la méthode CreateChildControls du contrôle pour restituer un champ, et moins sur le modèle de rendu, que dans le cas des contrôles de rendu de champ personnalisés que vous créez pour les navigateurs d'ordinateur. En outre, en développant des contrôles de rendu mobiles personnalisés, vous ne substituerez pas souvent la méthode CreateChildControls à proprement parler. À la place, vos contrôles de rendu mobiles personnalisés substitueront généralement une ou plusieurs des quatre méthodes qui sont appelées par la méthode CreateChildControls  :

Voir aussi

Référence

FieldTypes, élément (Types de champs)

FieldType, élément (types de champ)

Field, élément (types de champs)

Namespace Naming Guidelines

RenderPattern, élément (Types de champs)

AlternateTemplateName

BaseValidator

ControlTemplate

CreateChildControls

DefaultAlternateTemplateName

DefaultTemplateName

EnsureChildControls

FieldRenderingControl

GetValidatedString

ItemFieldValue

Label

OnLoad()

RegularExpressions

RenderingTemplate

SPControlMode

SPFieldText

SPFieldValidationException

Template

TemplateName

TextBox

TextField

ValidationRule

Value

Concepts

Procédure : créer une classe de champ personnalisé

Procédure : créer une définition de type de champ personnalisé

Déploiement de types de champs personnalisés

Validation des données du champ personnalisé

Procédure : créer un contrôle de rendu de champ

Procédure : créer des modèles de rendu de champ

Procédure : créer un type de champ personnalisé

Vue d'ensemble des solutions