# Développement de formulaires Web : Mode avancé

## Aperçu

Le mode avancé est spécialement conçu pour les développeurs en offrant un contrôle total sur tous les aspects d'un formulaire Web. Cela permet une plus grande flexibilité et offre plus de possibilités pour les fonctions pouvant entrer dans le formulaire Web.

## Création de l'application Web

### Outils de développement suggérés

* Visual Web Developer Express 2015 ou version supérieure
* Visual Studio 2015 ou version supérieure

### Répertoire d'installation des formulaires Web

Nous vous suggérons fortement de stocker tous vos formulaires Web dans le répertoire  `\wfgen\wfapps\webforms` (p.ex. : `\wfgen\wfapps\webforms\MonFormulaireWeb`).

Notez que si vous modifiez votre processus WorkflowGen et que vous devez modifier le `MonFormulaireWeb` associé en raison de ces modifications, vous devez au préalable dupliquer `MonFormulaireWeb`, puis créer une autre application IIS. Sinon, les deux versions du processus utiliseront le même `MonFormulaireWeb` modifié.

### Créez l'application dans IIS

L'application du formulaire Web doit être déclarée en tant qu'application dans IIS pour être reconnue en tant qu'application de formulaire Web .NET. Suivez ces instructions pour déclarer votre répertoire de formulaires Web en tant qu'application IIS :

#### Pour IIS 7 ou version ultérieure

1. Ouvrez **Gestionnaire IIS**. <br>
2. Accédez à l'emplacement de votre formulaire Web, qui doit se trouver dans le nœud **Site Web par défaut** sous `\wfgen\wfapps\webforms\MonFormulaireWeb`.<br>
3. Faites un clic droit sur **MonFormulaireWeb** et choisissez **Convertir en application**.<br>
4. Sélectionnez le pool d'applications utilisé par votre site et un autre pool d'applications spécifique.<br>
5. Cliquez sur **OK**.

## Création du projet avec Visual Studio

### Créez le projet

1. Ouvrez Visual Studio et sélectionnez **Fichier > Nouveau site Web**.<br>
2. Choisissez **Site Web ASP.NET**.<br>
3. Choisissez **Système de fichiers** dans la liste déroulante **Emplacement**.<br>
4. Cliquez sur **Parcourir**, puis choisissez l'emplacement de votre site Web ASP.NET.<br>
5. Cliquez sur **OK**.

### Créez un DataSet typé

Vous devrez créer un nouvel élément DataSet dans votre projet et y ajouter un DataTable `Table1`. Suivez ces étapes afin d'ajouter un nouveau DataSet dans votre projet Web :

1. Faites un clic droit sur votre projet et sélectionnez **Ajouter un nouvel élément...**<br>
2. Choisissez **DataSet**, puis cliquez sur **Ajouter**.<br>
3. Une fenêtre contextuelle apparaîtra vous demandant de choisir une connexion de données; cliquez sur **Annuler** car un DataSet ne peut pas être attaché à une source de données spécifique (il sera à la place envoyé dynamiquement lors de l'exécution).<br>
4. Faites un clic droit dans l'espace vide et sélectionnez **Ajouter > DataTable**. <br>
5. Renommez `DataTable1` en `Table1`.<br>
6. Ajoutez tous vos noms de champ de formulaire et les paramètres IN, OUT et INOUT en tant que colonnes dans ce tableau.<br>

   ✏️ **Note :** Il est nécessaire de reconstruire votre formulaire Web chaque fois que vous modifiez cette définition de DataSet.<br>
7. Ajoutez une variable DataSet à votre code `Default.aspx.cs` et instanciez-la dans le constructeur par défaut de votre classe. Si votre nom de classe est `Form`, le code ressemblera à ceci pour l'instant :

   ```csharp
   public partial class Form : WorkflowGen.My.Web.UI.WebForms.WorkflowPage
   {
    protected DataSet1 formData;

    public Form() : base()
    {
        formData = new DataSet1();
    }
   ```

### Obtenir des messages d'erreur détaillés

Par défaut, vous n'aurez aucun fichier `web.config` dans votre projet Web si vous utilisez C# comme langage de développement dans l'IDE de Microsoft Visual Studio. Pour afficher des messages d'erreur complets lorsque vous souhaitez déboguer, vous devez disposer d'un fichier `web.config`. Pour ajouter un fichier `web.config` par défaut à votre projet, procédez comme suit :

1. Faites un clic droit sur le nom de votre projet, puis cliquez sur **Ajouter un nouvel élément...**<br>
2. Choisissez **Fichier de configuration Web**, puis cliquez sur **OK**.

Afin de pouvoir voir les messages d'erreur complets, modifiez les propriétés suivantes dans le fichier `web.config` :

1. Assurez-vous que cette ligne est définie sur `"true"` :

   ```markup
   <compilation debug="true" />
   ```
2. Assurez-vous que le suivant n'est pas commenté et que la propriété `mode` est définie sur `"Off"` :

   ```markup
   <customErrors mode="Off" defaultRedirect="GenericErrorPage.htm">
       <error statusCode="403" redirect="NoAccess.htm" />
       <error statusCode="404" redirect="FileNotFound.htm" />
   </customErrors>
   ```

## Implémentation de base

### Référence

Vous devez ajouter une référence à `WorkflowGen.My.dll` dans votre projet Web, puis ajouter cette instruction au début de votre formulaire Web :

```csharp
using WorkflowGen.My.Web.UI.WebForms;
```

### Héritage de classe

Votre formulaire Web doit hériter de la classe WorkflowPage contenue dans l'espace de noms `WorfklowGen.My.Web.UI.WebForms`.

### Utilisation du mode avancé

Lorsque vous utilisez le mode avancé de WorkflowPage, vous devez spécifier que vous n'utilisez pas le mode simple. Utilisez le code suivant pour ce faire :

```csharp
public partial class Form : WorkflowGen.My.Web.UI.WebForms.WorkflowPage
{
    protected DataSet1 formData;

    public Form() : base()
    {

// Définissez la propriété SimpleMode sur False pour utiliser le mode avancé
    IsSimpleMode = false;
    formData = new DataSet1();
    }
}
```

### Méthode `Page_Load`

La première chose à faire dans la méthode `Page_Load` est d'appeler la méthode `FillFormData()` pour remplir les données dans vos données de formulaire. La `Page_Load` est également l'endroit où apporter des modifications aux propriétés de WorkflowPage. Vous pouvez donner un DataSet ou un XmlDocument à la méthode `FillFormData()`.

```csharp
protected void Page_Load(object sender, System.EventArgs e)
{
    // Remplissez vos données de formulaire ici
    FillFormData(formData);

    // Liez les données du formulaire aux champs du formulaire Web. (Ce n'est pas obligatoire,
    // cela dépend de la manière dont vous souhaitez gérer les données de votre formulaire)

if (!Page.IsPostBack)
    {

BindFormDataToFields(formData);
    }

    // Tout traitement supplémentaire ira ici
    // ...
}
```

### Enregistrement des données de formulaire

Les données de formulaire doivent être enregistrées sur toute publication (« postback ») qui modifie les données du formulaire. Si vous ne l'enregistrez pas avant la fin de la publication, toutes les modifications seront perdues car la méthode `FillFormData()` dans l'événement `Page_Load` remplacera les modifications avec les anciennes données.

Pour enregistrer vos données de formulaire dans EFORMASPX, vous devez appeler la méthode `SaveFormData()` à partir de WorkflowPage. Vous pouvez attribuer un DataSet ou un XmlDocument à la méthode `SaveFormData()`.

```csharp
protected void AnyServerSideEventModifyingFormData(object sender, ...)
{
    // Modifiez les données du formulaire ...
    formData.Tables["TableExpense"].Rows.RemoveAt(e.Item.ItemIndex);

    // Reliez le(s) contrôle(s) pour voir les modifications sur le formulaire Web
    DataList1.DataBind();

    // Enregistrez les données du formulaire
        this.SaveFormData(formData);
}
```

### Mise à jour des données de formulaire avec les valeurs du formulaire Web

Vous souhaiterez généralement mettre à jour vos données de formulaire avec les valeurs du formulaire Web avant de soumettre les données du formulaire à WorkflowGen. Cela peut être fait pour tous les champs qui sont liés dans le `Table1` de vos données de formulaire en appelant la méthode `SaveFieldsData(DataSet)`. La méthode essaiera de trouver des contrôles dans la page qui ont les mêmes IDs que les colonnes `Table1`, et lorsqu'elle en trouve un, elle met à jour la valeur de la donnée de formulaire avec la valeur du contrôle.

```csharp
protected void Submit_Click(object sender, System.EventArgs e)
{
    // Mettre à jour automatiquement les données du formulaire avec les valeurs du formulaire Web
    this.SaveFieldsData(formData);
}
```

{% hint style="info" %}
Cette méthode supporte uniquement les DataSet. Les champs qui sont mis à jour doivent se trouver dans une table nommée `Table1`.
{% endhint %}

### Soumission au workflow

Une fois qu'il est temps de tout soumettre au workflow (via EFORMASPX), vous devez appeler la méthode `WorkflowPageSubmitToWorkflow()`. Cette méthode doit recevoir vos données de formulaire si vous souhaitez les enregistrer en même temps. Vous pouvez également séparer manuellement ces appels en appelant `SubmitToWorkflow` sans aucun paramètre; cependant, si vous faites cela, les données de votre formulaire ne seront pas mises à jour si vous n'appelez pas explicitement `SaveFormData(formData)` avant de soumettre.

```csharp
protected void Submit_Click(object sender, System.EventArgs e)
{

// Tout traitement avant de soumettre va ici (p.ex. : validation,
// modification des données etc.)
    // ...

    // Soumet tout au workflow et crée l'archive de formulaire si
    // nécessaire.
    this.SubmitToWorkflow(formData);
}
```

## Gestion de la validation des champs

### Aperçu

WorkflowPage crée automatiquement des contrôles `RequiredFieldValidator` dans votre page pour valider les champs qui ont été écrits dans le paramètre `FORM_FIELDS_REQUIRED` dans toutes vos actions EFORMASPX. Ces validations peuvent être placées sur l'un des types de contrôle suivants :

* `TextBox`
* `RadioButtonList`
* `DropDownList`
* `ListBox`
* `FileUpload`
* `HtmlInputFile`

Si vous souhaitez avoir un message personnalisé, vous devez modifier la propriété `RequiredFieldsErrorMessage`. Assurez-vous d'avoir le symbole `{0}` dans votre message personnalisé. Si vous ne placez pas de balise `{0}` quelque part dans votre message, une exception sera levée car il ne serait pas logique d'avoir une liste de champs obligatoires sans savoir quels champs doivent être remplis.

Les contrôles `RequiredFieldValidator` qui sont créés ont leurs propriétés `ValidationGroup` définies sur `WFGENPage`. Cela signifie que la validation de ces validateurs ne sera effectuée que si le contrôle qui déclenche la validation a sa propriété `ValidationGroup` définie sur la même valeur. Par défaut, si vous avez un contrôle bouton `SubmitButton` dans votre page, son `ValidationGroup` est automatiquement modifié. Si vous utilisez un autre identifiant pour le bouton de soumission, vous devez définir vous-même le `ValidationGroup`, sinon les champs obligatoires ne seront pas validés comme prévu lors de la soumission de la page.

### Validation du type de données

Lorsque vous spécifiez le type de données d'un champ à l'aide de l'attribut `FieldDataType`, des validateurs sont automatiquement insérés dans votre page pour valider les types de données `Date` et `Numeric`.

* Les champs de type DATE sont validés à l'aide d'un `RangeValidator` avec la propriété `MinimumValue` définie sur `DateTime.MinimumValue` et la propriété `MaximumValue` définie sur `DateTime.MaximumValue`.<br>
* Les champs de type NUMERIC sont validés à l'aide d'un `RangeValidator` avec la propriété `MinimumValue` définie sur `Double.MinimumValue` et la propriété `MaximumValue` définie sur `Double.MaximumValue`.

Les contrôles `RangeValidator` ont la convention d'affectation de noms suivante  : `WFGEN_RV_FIELD_ID`.

Si vous créez vos propres contrôles `RangeValidator` pour valider les champs sur lesquels vous avez défini l'attribut `FieldDataType`, WorkflowPage ne crée pas automatiquement de `RangeValidator` pour ces champs.

Les contrôles `RangeValidator` qui sont créés ont leurs propriétés `ValidationGroup` définies sur `WFGENPage`. Cela signifie que la validation de ces validateurs ne sera effectuée que si le contrôle qui déclenche la validation a sa propriété `ValidationGroup` définie sur la même valeur. Par défaut, si vous avez un contrôle bouton `SubmitButton` dans votre page, son `ValidationGroup` est automatiquement modifié. Si vous utilisez un autre identifiant pour le bouton de soumission, vous devez définir vous-même le `ValidationGroup`, sinon les champs ne seront pas validés comme prévu lors de la soumission de la page.

### Validation personnalisée

Si vous souhaitez effectuer vos propres validations personnalisées, vous pouvez toujours créer vos contrôles `RequiredFieldValidator` ou `RangeValidator` sur les champs où vous avez spécifié l'attribut `FieldDataType`, et WorkflowPage ne créera pas automatiquement des contrôles `RequiredFieldValidator` ou `RangeValidator` pour ces contrôles particuliers.

Si vous souhaitez effectuer plus de validations sur l'un de vos champs à l'aide d'autres validateurs .NET (tels que les contrôles `CompareValidator`, `CustomValidator` ou `RegularExpressionValidator`), vous devrez modifier les propriétés `ValidationGroup` de ces validateurs en `WFGENPage`, sinon la validation ne sera pas effectuée pour les contrôles ciblés lors de la soumission du formulaire.

#### 📌 Exemple

```aspnet
<asp:RegularExpressionValidator ID="RegValidatorExample" runat="server"
ErrorMessage="Votre message d'erreur" ControlToValidate="VotreContrôle"
Display="Dynamic" ValidationGroup="WFGENPage" ValidationExpression="\w+([-
+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*">
</asp:RegularExpressionValidator>
```

## Champs en lecture seule

### Aperçu

WorkflowPage peut automatiquement rendre certains champs en lecture seule ou désactivés (selon les types de contrôle) pour les champs du paramètre `FORM_FIELDS_READONLY`. Les types de contrôle suivants seront définis en lecture seule ou désactivés s'ils se trouvent dans `FORM_FIELDS_READONLY` :

* `TextBox`
* `RadioButton`
* `RadioButtonList`
* `CheckBox`
* `CheckBoxList`
* `DropDownList`
* `ListBox`
* `FileUpload`
* `HtmlInputFile`

## Gestion de la colorisation des champs

### Aperçu

WorkflowPage modifie automatiquement l'apparence des contrôles `FORM_FIELDS_REQUIRED` et `FORM_FIELDS_READONLY` en fonction de sa propriété `FieldsColorization`.

La propriété `FieldsColorization` est une instance d'une énumération qui peut avoir les valeurs suivantes :

* `Automatic`
* `CSS`
* `None`

### Mode Automatic

Le mode **Automatic** utilise les propriétés suivantes pour coloriser les champs :

* `RequiredFieldsBorderColor`
* `ReadOnlyFieldsBorderColor`

Certains types de contrôle ont leurs bordures colorisées tandis que d'autres ont leurs couleurs de texte modifiées (pour des raisons esthétiques).

Les contrôles suivants verront leur couleur de texte (propriété `ForeColor`) modifiée si la couleur n'est pas `Color.Empty` dans leurs propriétés correspondantes :

* `DropDownList`
* `CheckBoxList`
* `RadioButtonList`

Les autres contrôles verront leurs couleurs de bordure modifiées si la couleur n'est pas `Color.Empty` dans leurs propriétés correspondantes.

### Mode CSS

Au lieu de modifier directement le style, le mode **CSS** modifie les propriétés `CssClass` des contrôles comme indiqué dans l'exemple ci-dessous, ce qui vous donne beaucoup plus de flexibilité pour avoir l'apparence exacte que vous souhaitez dans votre formulaire Web.

#### 📌 Exemple

* Si `TextBox1` a sa propriété `CssClass` définie sur `FieldValueCell` et qu'il s'agit d'un champ obligatoire, `CssClass1` sera remplacé par `FieldValueCell-required`.<br>
* Si `TextBox1` n'a pas de propriété `CssClass`, `CssClass` sera remplacé par `Required`.

### Mode None

Le mode **None** ne modifiera la couleur ou le style des contrôles de votre formulaire Web. Ce mode désactive complètement la colorisation automatique ou la colorisation CSS.

## Gestion de l'archive de formulaire

### Feuille de style CSS

Vous pouvez personnaliser l'apparence de votre archive de formulaire à l'aide du fichier `form_archive.css`.

Vos styles CSS doivent être situés dans un sous-répertoire appelé  `\css` et votre fichier de feuille de style d'archive de formulaire doit être appelé `form_archive.css`, car WorkflowPage recherchera cet emplacement particulier et ce nom de fichier pour le trouver, puis remplacera les styles d'archive de formulaire par les styles contenus dans ce fichier.

Si ces valeurs par défaut ne sont pas celles que vous souhaitez utiliser, vous pouvez toujours modifier la propriété `FormArchiveCssPath`, dont la valeur par défaut est `\css\form_archive.css`. Si aucun fichier `form_archive.css` n'est créé, l'archive de formulaire aura la même apparence que le formulaire Web, mais les champs seront tous définis en lecture seule ou désactivés.

### Masquer les champs

Par défaut, le bouton dans votre page avec l'ID `SubmitButton` sera automatiquement masqué dans l'archive de formulaire.

Si vous souhaitez masquer d'autres champs dans l'archive de formulaire, utilisez le paramètre `FORM_FIELDS_ARCHIVE_HIDDEN`. Les contrôles répertoriés dans ce paramètre seront automatiquement masqués lors de la création de l'archive de formulaire.

{% hint style="info" %}
Les contrôles qui ne sont pas `runat=server` dans votre formulaire Web ne seront pas masqués.
{% endhint %}

Vous voudrez parfois personnaliser la mise en page du formulaire archivé. Pour ce faire, vous devrez remplacer la méthode WorkflowPage `ChangeFormArchiveLayout()`.

```csharp
protected override void ChangeFormArchiveLayout()
{
    // Effectuez des traitements personnalisés ici
    // ...

    // Assurez-vous d'appeler la base ChangeFormArchiveLayout si vous souhaitez
    // que les champs soient automatiquement mis en lecture seule et masquer
    // les champs répertoriés dans FORM_FIELDS_ARCHIVE_HIDDEN
    base.ChangeFormArchiveLayout();
}
```

Si vous voulez encore plus de flexibilité avec la création d'archives de formulaires, vous pouvez remplacer la méthode `GetFormArchive()`. Cette méthode doit renvoyer une chaîne contenant le HTML de l'archive de formulaire.

```csharp
protected override string GetFormArchive()
{
    // Construisez le html de l'archive de formulaire
    
    // ...

    // Renvoyer le résultat html

return htmlResult;
}
```

## Gestion des pièces jointes

Lorsque vous avez un contrôle `FileUpload` dans votre formulaire Web, vous souhaiterez utiliser la méthode `SaveFileAttachment()` dans WorkflowPage. Cette méthode est utilisée pour enregistrer le fichier dans le sous-répertoire  `\upload` dans le chemin de stockage EFORMASPX et récupérer le nom de fichier du fichier publié.

```csharp
protected void Submit_Click(object sender, System.EventArgs e)
{
    // ...

    // Enregistrez la pièce jointe dans EFORMASPX et mettez à jour
    // le nom du fichier dans les données du formulaire
    formData.Tables["Table1"].Rows[0]["TEST_UPLOAD"] = 
SaveFileAttachment(TEST_UPLOAD.PostedFile);

    // ...
}
```

Si vous avez plusieurs pièces jointes en une seule action, vous devez envisager de renommer les fichiers publiés manuellement, car si l'utilisateur envoie deux fichiers différents portant le même nom, les fichiers se remplaceront. Pour enregistrer la pièce jointe avec un nom spécifié, utilisez la méthode surchargée `SaveFileAttachment()`.

```csharp
protected void Submit_Click(object sender, System.EventArgs e)
{

// ...

    // Enregistrez la pièce jointe dans EFORMASPX et mettez à jour
    // le nom du fichier dans les données du formulaire
    formData.Tables["Table1"].Rows[0]["TEST_UPLOAD"] = 
SaveFileAttachment(TEST_UPLOAD.PostedFile,
"NomDeFichierQueVousChoisissez.ext");

    // ...
}
```

## Gestion des ressources

### Ajouter des ressources à votre projet Web

1. Faites un clic droit sur la racine de votre site Web, puis sélectionnez **Ajouter un nouvel élément...**<br>
2. Choisissez **Fichier de ressources** et entrez le nom souhaité pour votre fichier de ressources.<br>
3. Cliquez sur **Ajouter**. Ce fichier contiendra les ressources par défaut pour votre formulaire Web (`en-US`).<br>
4. Ajoutez un fichier de ressources pour chaque langue que vous souhaitez gérer pour votre formulaire Web. Le nom de fichier doit se terminer par `culture-code.resx`.\
   \
   📌 **Exemple :** `Strings.fr-FR.resx` serait le nom de fichier de la langue française de France.

Lorsque vous souhaitez utiliser les ressources dans votre formulaire Web, il vous suffit d'utiliser l'espace de noms `System.Resources`, et toutes vos ressources seront automatiquement fortement typées. Cela signifie que vous pouvez accéder à tout le contenu de vos fichiers de ressources avec des propriétés d'objet.

## Gestion du GridView

### Aperçu

Cette section explique comment utiliser un GridView en mode avancé.

### DataTable

La première chose que vous devez faire est d'ajouter un DataTable au DataSet de vos données de formulaire qui représente les données gérées du GridView.

{% hint style="info" %}
Il est important que ce DataTable ait une clé primaire.
{% endhint %}

### Objet métier

Vous devez maintenant concevoir un objet métier qui encapsulera les opérations possibles sur votre DataTable. Voici un exemple d'objet métier pour le DataTable  `PEOPLE_LIST` :

```csharp
public class PeopleListBusinessObject
{
    // Référence au DataTable people_list
    private FormData.PEOPLE_LISTDataTable peopleListTable;

    /// <summary>
    /// Constructeur qui affecte la référence de la table peopleListTable
    /// </summary>
    /// <param name="peopleListDataTable">The reference we need to populate our
    /// business object</param>
    public PeopleListBusinessObject(FormData.PEOPLE_LISTDataTable
peopleListDataTable)
    {
        peopleListTable = peopleListDataTable;
    }

    /// <summary>
    /// Returns the PeopleListDataTable, will be used by the ObjectDataSource
    /// </summary>
    /// <returns>A PEOPLE_LISTDataTable</returns>
    public FormData.PEOPLE_LISTDataTable GetPeopleList()
    {
        return peopleListTable;
    }

    /// <summary>
    /// Inserts / updates data into the PEOPLE_LIST DataTable, will be used by the
    /// ObjectDataSource
    /// </summary>
    /// <param name="ID">The Person ID</param>
    /// <param name="firstName">First name of the person</param>
    /// <param name="lastName">Last name of the person</param>
    public void UpdateOrInsertPerson(int ID, string firstName, string lastName)
    {
        FormData.PEOPLE_LISTRow tempRow = peopleListTable.Rows.Find(ID) as FormData.PEOPLE_LISTRow;!

        if (tempRow != null)
        {
            // we found a row, so we are updating it
            tempRow.FIRSTNAME = firstName;
            tempRow.LASTNAME = lastName;
        }
        else
        {
            // nous n'avons pas trouvé de ligne avec l'ID demandé, cela signifie que nous insérons
            peopleListTable.Rows.Add(firstName, lastName);
        }
    }

    /// <summary>
    /// Supprime une personne de la table de données PEOPLE_LIST qui sera utilisée par le
    /// ObjectDataSource
    /// </summary>
    /// <param name="ID"></param>
    public void DeletePerson(int ID)
    {
        FormData.PEOPLE_LISTRow tempRow = peopleListTable.Rows.Find(ID) as FormData.PEOPLE_LISTRow;
        peopleListTable.Rows.Remove(tempRow);
    }
}
```

### `ObjectDataSource`

L'étape suivante consiste à placer un `ObjectDataSource` dans votre page et à le lier à votre objet métier. Pour ce faire :

1. Glissez-déplacez l'`ObjectDataSource` sur votre formulaire Web en mode **Création**.<br>
2. Cliquez sur **Configurer la source de données**.<br>
3. Choisissez l'objet métier que vous avez créé précédemment.<br>
4. Sélectionnez la méthode appropriée pour chaque opération de données.​​

   ​​\
   ✏️ **Note :** Le GridView n'a pas les fonctions intégrées pour supporter les opérations d'insertion, nous allons donc utiliser la section **UPDATE** afin d'insérer des éléments. Ne choisissez aucune méthode pour la section **INSERT**.<br>
5. Cliquez sur **Terminer**.<br>
6. Ajoutez l'événement `ObjectCreating` pour gérer la création de l'`ObjectDataSource` avec la classe de l'objet métier.

   ```csharp
   protected void PeopleListObjectDataSource_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
       {
       // Attachez l'instance de PEOPLE_LIST à
       // PeopleListObjectDataSource
       e.ObjectInstance = new PeopleListBusinessObject(formData.PEOPLE_LIST);
       }
   ```

### GridView

1. Glissez-déplacez un GridView sur le formulaire Web, choisissez l'`ObjectDataSource` que vous avez créé à l'étape précédente comme DataSource et vérifiez les opérations que vous souhaitez activer dans votre GridView. (Voir [Activation de l'insertion dans le GridView](/vs-web-forms-fr/developpement-de-formulaires-web-mode-avance.md#activation-de-linsertion-dans-le-gridview) ci-dessous pour des instructions sur comment activer l'insertion dans un GridView.)<br>
2. Définissez la propriété `DataKeyNames` si vous souhaitez activer la modification et l'insertion dans votre GridView.<br>
3. Il est recommandé de définir le champ `ID` en lecture seule en cliquant sur **Modifier les colonnes...** et en définissant la propriété `ReadOnly` du champ lié à l'ID sur `True`.

### Activation de l'insertion dans le GridView

La solution de contournement pour l'insertion dans un GridView consiste à ajouter un bouton pour insérer manuellement une nouvelle ligne dans le DataTable `PEOPLE_LIST` lorsque quelqu'un clique dessus. Pour ce faire :

1. Glissez-déplacez un `LinkButton` sous votre GridView, puis double-cliquez sur le `LinkButton` et ajoutez-y le code suivant:

   ```csharp
   protected void InsertPerson_Click(object sender, EventArgs e)
    {
    // Insérez une nouvelle ligne dans la table de données PEOPLE_LIST,
    // changez le EditIndex afin que nous puissions remplir les informations
    // de la nouvelle personne, puis reliez PEOPLE_LIST.
    formData.PEOPLE_LIST.AddPEOPLE_LISTRow("", "");
    PEOPLE_LIST.EditIndex = formData.PEOPLE_LIST.Rows.Count - 1;
    PEOPLE_LIST.DataBind();
    }
   ```
2. Ce code ne supporte pas la pagination et le tri, vous devrez donc détecter vous-même le nouvel `EditIndex` si vous souhaitez activer la pagination et le tri dans votre GridView. Cela est dû au fait que le `EditIndex` n'est pas nécessairement le `PEOPLE_LIST.Rows.Count - 1` lorsque vous utilisez ces fonctions.

### Mise à jour des données de votre formulaire `OnRowDeleted` et `OnRowUpdated`

La dernière étape consiste à définir les événements `OnRowDeleted` et `OnRowUpdated` pour que GridView mette à jour vos données de formulaire à chaque modification. Pour ce faire, ajoutez le code suivant :

```csharp
protected void PEOPLE_LIST_RowUpdated(object sender,
 GridViewUpdatedEventArgs e)
    {
        // Lorsque nous mettons à jour une ligne,
        // nous enregistrons les données
        SaveFormData(formData);
    }
protected void PEOPLE_LIST_RowDeleted(object sender,
 GridViewDeletedEventArgs e)
    {
        // Lorsque nous supprimons une ligne,
        // nous enregistrons les données
        SaveFormData(formData);
    }
```

## Personnalisation du schéma `FormData` et séparation des données de formulaire des paramètres de formulaire

### Personnalisation du schéma FormData

Dans la section précédente, vous avez été invité à placer tous les paramètres et vos données de formulaire dans le même DataTable nommé `Table1`, mais vous pouvez toujours utiliser un autre nom de DataSet et un autre nom de DataTable si vous le souhaitez.

Notez, cependant, que si vous n'utilisez pas le nom `Table1` pour le DataTable, vous devez utiliser le paramètre `PARAMS_XPATH` dans toutes vos actions pour indiquer à EFORMASPX et WorkflowPage où ils doivent localiser les paramètres et les données du formulaire. Ce paramètre est un XPath qui pointe vers cette table. Si vous nommez votre DataSet `MyFormData` et que vous nommez votre table par défaut `MyParameters`, le paramètre `PARAMS_XPATH` doit contenir `MyFormData/MyParameters`, sinon votre processus ne fonctionnera pas.

Lorsque vous définissez un schéma personnalisé de cette façon, vous devez également inclure un fichier modèle `FORM_DATA` dans votre projet avec le même schéma vide :

```markup
<?xml version="1.0" encoding="utf-8" ?>
<MyFormData>
    <MyParameters>
    </MyParameters>
</MyFormData>
```

### Séparation des données de formulaire des paramètres de formulaire

Vous pouvez séparer les paramètres d'action de vos données de formulaire, mais vous devrez utiliser l'emplacement XPath complet de vos données de formulaire comme nom de paramètre si vous souhaitez les utiliser comme paramètres d'action. Par exemple, si vous avez un champ nommé `REQUEST_FIRSTNAME` dans votre formulaire Web et que vous souhaitez placer ces données dans une autre table (p.ex. `MyData`), vous déclarez le paramètre avec le nom `/MesDonnnéesFormulaire/MesDonnées/REQUEST_FIRSTNAME`.

Notez que si vous utilisez des expressions XPath personnalisées pour vos noms de paramètres d'action, vous devrez également télécharger un `FORM_DATA` personnalisé dans votre processus qui contient des nœuds vides pour ces paramètres.

Voici un exemple complet d'action de processus qui utiliserait des DataTables séparés pour les paramètres et pour les données du formulaire :

```markup
<?xml version="1.0" encoding="utf-8" ?>
<MyFormData>
    <MyParameters>
    </MyParameters>
    <MyData>
        <REQUEST_NUMBER />
        <REQUEST_FIRSTNAME />
        <REQUEST_LASTNAME />
        <REQUEST_DATE />
    </MyData>
</MyFormData>
```

#### Structure de DataSet

<div align="left"><img src="/files/-MO8tA8zOLi22qQL0Apt" alt=""></div>

#### Paramètres d'action

<div align="left"><img src="/files/-MO8tHq38g14G9maApRl" alt=""></div>

## Utilisation des UserControls Web dans les formulaires Web

Si vous prévoyez d'utiliser des UserControls pour encapsuler certaines parties de vos formulaires Web qui seront répétées d'un formulaire Web à un autre, vous pouvez les utiliser avec WorkflowGen.My.

Vous devez disposer des informations suivantes pour les utiliser correctement :

* Pour chaque contrôle présent dans le UserControl, WorkflowGen.My créera un nœud dans `Table1` du jeu de donnée `FormData`, préfixé par l'ID du contrôle utilisateur dans la page.\
  \
  Par exemple, si vous avez un UserControl dans votre page avec l'ID `HEADER_UC` qui contient une zone de texte avec l'ID `FIRST_NAME`, le champ sera accessible via FormData avec le nom `HEADER_UC.FIRST_NAME`.<br>
* Si vous souhaitez accéder à ce champ via un paramètre WorkflowGen, vous devrez utiliser cette convention pour accéder au champ. Si vous souhaitez utiliser une macro qui envoie le prénom de l'utilisateur dans le champ `HEADER_UC.FIRST_NAME`, vous devrez utiliser ce nom comme nom de paramètre dans le paramètre d'action WorkflowGen.<br>
* Si vous souhaitez définir un champ situé dans un UserControl pour qu'il soit considéré comme requis par WorkflowGen.My, vous utilisez toujours la convention ci-dessus pour répertorier ce champ dans le paramètre `FORM_FIELDS_REQUIRED`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.workflowgen.com/vs-web-forms-fr/developpement-de-formulaires-web-mode-avance.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
