Partager via


Mise à jour et suppression de données binaires existantes (C#)

par Scott Mitchell

Télécharger le PDF

Dans les tutoriels précédents, nous avons vu comment le contrôle GridView simplifie la modification et la suppression des données de texte. Dans ce tutoriel, nous voyons comment le contrôle GridView permet également de modifier et de supprimer des données binaires, que ces données binaires soient enregistrées dans la base de données ou stockées dans le système de fichiers.

Introduction

Au cours des trois derniers tutoriels, nous avons ajouté un certain nombre de fonctionnalités pour travailler avec des données binaires. Nous avons commencé par ajouter une BrochurePath colonne à la Categories table et mis à jour l’architecture en conséquence. Nous avons également ajouté des méthodes couche d’accès aux données et couche logique métier pour travailler avec la colonne existante Picture de la table Categories, qui contient le contenu binaire d’un fichier image. Nous avons créé des pages web pour présenter les données binaires dans un GridView un lien de téléchargement pour la brochure, avec l’image de catégorie affichée dans un <img> élément et avons ajouté un DetailsView pour permettre aux utilisateurs d’ajouter une nouvelle catégorie et de charger ses données de brochure et d’image.

Tout ce qui reste à implémenter est la possibilité de modifier et de supprimer des catégories existantes, ce que nous allons accomplir dans ce tutoriel à l’aide des fonctionnalités intégrées de modification et de suppression de GridView. Lors de la modification d’une catégorie, l’utilisateur peut éventuellement charger une nouvelle image ou faire en savoir plus sur la catégorie existante. Pour la brochure, ils peuvent choisir d’utiliser la brochure existante, de télécharger une nouvelle brochure ou d’indiquer que la catégorie n’a plus de brochure associée. Commençons !

Étape 1 : Mise à jour de la couche d’accès aux données

Le DAL a généré Insertautomatiquement les méthodes , Updateet Delete , mais ces méthodes ont été générées en fonction de la CategoriesTableAdapter requête s main, qui n’inclut pas la Picture colonne. Par conséquent, les méthodes et Update n’incluent Insert pas de paramètres pour spécifier les données binaires pour l’image de catégorie. Comme nous l’avons fait dans le tutoriel précédent, nous devons créer une nouvelle méthode TableAdapter pour mettre à jour la table lors de la Categories spécification de données binaires.

Ouvrez le DataSet typé et, à partir du Designer, cliquez avec le bouton droit sur l’en-tête CategoriesTableAdapter s et choisissez Ajouter une requête dans le menu contextuel pour lancer l’Assistant Configuration de requête TableAdapter. Cet Assistant commence par nous demander comment la requête TableAdapter doit accéder à la base de données. Choisissez Utiliser des instructions SQL, puis cliquez sur Suivant. L’étape suivante invite à générer le type de requête. Étant donné que nous créons à nouveau une requête pour ajouter un nouvel enregistrement à la Categories table, choisissez METTRE À JOUR, puis cliquez sur Suivant.

Sélectionnez l’option UPDATE

Figure 1 : Sélectionnez l’option UPDATE (Cliquez pour afficher l’image en taille réelle)

Nous devons maintenant spécifier l’instruction UPDATE SQL. L’Assistant suggère automatiquement une UPDATE instruction correspondant à la requête TableAdapter s main (qui met à jour les CategoryNamevaleurs , Descriptionet BrochurePath ). Modifiez l’instruction afin que la Picture colonne soit incluse avec un @Picture paramètre, comme suit :

UPDATE [Categories] SET 
    [CategoryName] = @CategoryName, 
    [Description] = @Description, 
    [BrochurePath] = @BrochurePath ,
    [Picture] = @Picture
WHERE (([CategoryID] = @Original_CategoryID))

Le dernier écran de l’Assistant nous demande de nommer la nouvelle méthode TableAdapter. Entrez UpdateWithPicture et cliquez sur Terminer.

Nommez la nouvelle méthode TableAdapter UpdateWithPicture

Figure 2 : Nommez la nouvelle méthode UpdateWithPicture TableAdapter (cliquez pour afficher l’image en taille réelle)

Étape 2 : Ajout des méthodes de couche logique métier

En plus de mettre à jour le DAL, nous devons mettre à jour la BLL pour inclure des méthodes de mise à jour et de suppression d’une catégorie. Il s’agit des méthodes qui seront appelées à partir de la couche de présentation.

Pour supprimer une catégorie, nous pouvons utiliser la CategoriesTableAdapter méthode générée automatiquement Delete s. Ajoutez la méthode suivante à la classe CategoriesBLL :

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteCategory(int categoryID)
{
    int rowsAffected = Adapter.Delete(categoryID);
    // Return true if precisely one row was deleted, otherwise false
    return rowsAffected == 1;
}

Pour ce tutoriel, nous allons créer deux méthodes pour mettre à jour une catégorie : une qui attend les données d’image binaires et appelle la UpdateWithPicture méthode que nous venons d’ajouter à et CategoriesTableAdapter une autre qui accepte uniquement les CategoryNamevaleurs , Descriptionet et BrochurePath utilise CategoriesTableAdapter l’instruction générée Update automatiquement par la classe. La raison d’être de l’utilisation de deux méthodes est que, dans certaines circonstances, un utilisateur peut vouloir mettre à jour l’image de catégorie avec ses autres champs, auquel cas l’utilisateur devra charger la nouvelle image. Les données binaires de l’image téléchargées peuvent ensuite être utilisées dans l’instruction UPDATE . Dans d’autres cas, l’utilisateur peut uniquement être intéressé par la mise à jour, par exemple, du nom et de la description. Mais si l’instruction UPDATE attend également les données binaires pour la Picture colonne, nous devons également fournir ces informations. Cela nécessite un déplacement supplémentaire dans la base de données pour ramener les données d’image de l’enregistrement en cours de modification. Par conséquent, nous voulons deux UPDATE méthodes. La couche logique métier détermine celle à utiliser en fonction si les données d’image sont fournies lors de la mise à jour de la catégorie.

Pour faciliter cela, ajoutez deux méthodes à la CategoriesBLL classe, toutes deux nommées UpdateCategory. Le premier doit accepter trois string s, un byte tableau et un comme paramètres d’entrée int ; le second, seulement trois string s et un int. Les string paramètres d’entrée sont pour le nom de catégorie, la description et le chemin du fichier de brochure, le byte tableau correspond au contenu binaire de l’image de catégorie s et le int identifie le CategoryID de l’enregistrement à mettre à jour. Notez que la première surcharge appelle la seconde si le tableau transmis byte est null:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateCategory(string categoryName, string description, 
    string brochurePath, byte[] picture, int categoryID)
{
    // If no picture is specified, use other overload
    if (picture == null)
        return UpdateCategory(categoryName, description, brochurePath, categoryID);
    // Update picture, as well
    int rowsAffected = Adapter.UpdateWithPicture
        (categoryName, description, brochurePath, picture, categoryID);
    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}
[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateCategory(string categoryName, string description, 
    string brochurePath, int categoryID)
{
    int rowsAffected = Adapter.Update
        (categoryName, description, brochurePath, categoryID);
    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

Étape 3 : Copie sur les fonctionnalités d’insertion et d’affichage

Dans le tutoriel précédent , nous avons créé une page nommée UploadInDetailsView.aspx qui répertorie toutes les catégories d’un GridView et fournit un DetailsView pour ajouter de nouvelles catégories au système. Dans ce tutoriel, nous allons étendre GridView pour inclure la prise en charge de la modification et de la suppression. Au lieu de continuer à travailler à partir de UploadInDetailsView.aspx, placez plutôt ce tutoriel s modifications dans la UpdatingAndDeleting.aspx page à partir du même dossier, ~/BinaryData. Copiez et collez le balisage déclaratif et le code de dans UploadInDetailsView.aspxUpdatingAndDeleting.aspx.

Commencez par ouvrir la UploadInDetailsView.aspx page. Copiez toute la syntaxe déclarative au sein de l’élément <asp:Content> , comme illustré dans la figure 3. Ensuite, ouvrez UpdatingAndDeleting.aspx et collez ce balisage dans son <asp:Content> élément. De même, copiez le code de la classe code-behind de la UploadInDetailsView.aspx page vers UpdatingAndDeleting.aspx.

Copiez le balisage déclaratif à partir de UploadInDetailsView.aspx

Figure 3 : Copier le balisage déclaratif à partir de UploadInDetailsView.aspx (Cliquer pour afficher l’image en taille réelle)

Après avoir copié le balisage et le code déclaratifs, accédez à UpdatingAndDeleting.aspx. Vous devez voir la même sortie et avoir la même expérience utilisateur qu’avec UploadInDetailsView.aspx la page du tutoriel précédent.

Étape 4 : Ajout de la prise en charge de la suppression à ObjectDataSource et GridView

Comme nous l’avons vu dans le didacticiel Vue d’ensemble de l’insertion, de la mise à jour et de la suppression de données, GridView fournit des fonctionnalités de suppression intégrées et ces fonctionnalités peuvent être activées à la case à cocher si la source de données sous-jacente de la grille prend en charge la suppression. Actuellement, l’ObjetDataSource auquel GridView est lié (CategoriesDataSource) ne prend pas en charge la suppression.

Pour y remédier, cliquez sur l’option Configurer la source de données à partir de la balise active ObjectDataSource pour lancer l’Assistant. Le premier écran montre que ObjectDataSource est configuré pour fonctionner avec la CategoriesBLL classe . Appuyez sur Suivant. Actuellement, seules les propriétés ObjectDataSource InsertMethod et SelectMethod sont spécifiées. Toutefois, l’Assistant a rempli automatiquement les listes déroulantes dans les onglets UPDATE et DELETE avec les UpdateCategory méthodes et DeleteCategory , respectivement. En effet, dans la CategoriesBLL classe, nous avons marqué ces méthodes en utilisant comme DataObjectMethodAttribute méthodes par défaut pour la mise à jour et la suppression.

Pour l’instant, définissez la liste déroulante s de l’onglet UPDATE sur (Aucun), mais laissez la liste déroulante s de l’onglet DELETE définie sur DeleteCategory. Nous revenons à cet Assistant à l’étape 6 pour ajouter la prise en charge de la mise à jour.

Configurer ObjectDataSource pour utiliser la méthode DeleteCategory

Figure 4 : Configurer ObjectDataSource pour utiliser la DeleteCategory méthode (Cliquer pour afficher l’image en taille réelle)

Notes

À la fin de l’Assistant, Visual Studio peut vous demander si vous souhaitez actualiser les champs et les clés, ce qui régénérera les champs des contrôles web de données. Choisissez Non, car si vous choisissez Oui, vous remplacez toutes les personnalisations de champ que vous avez effectuées.

ObjectDataSource inclut désormais une valeur pour sa DeleteMethod propriété, ainsi qu’un DeleteParameter. Rappelez-vous que lorsque vous utilisez l’Assistant pour spécifier les méthodes, Visual Studio définit la propriété ObjectDataSource OldValuesParameterFormatString sur original_{0}, ce qui provoque des problèmes avec les appels de méthode de mise à jour et de suppression. Par conséquent, effacez complètement cette propriété ou réinitialisez-la à la valeur par défaut, {0}. Si vous devez actualiser votre mémoire sur cette propriété ObjectDataSource, consultez le didacticiel Vue d’ensemble de l’insertion, de la mise à jour et de la suppression de données .

Après avoir terminé l’Assistant et résolu le OldValuesParameterFormatString, le balisage déclaratif d’ObjectDataSource doit ressembler à ce qui suit :

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL" InsertMethod="InsertWithPicture" 
    DeleteMethod="DeleteCategory">
    <InsertParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
    </InsertParameters>
    <DeleteParameters>
        <asp:Parameter Name="categoryID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Après avoir configuré ObjectDataSource, ajoutez des fonctionnalités de suppression à GridView en cochant la case Activer la suppression de la balise active de GridView. Cela ajoute un Champ de commande au GridView dont ShowDeleteButton la propriété est définie sur true.

Activer la prise en charge de la suppression dans GridView

Figure 5 : Activer la prise en charge de la suppression dans GridView (cliquer pour afficher l’image en taille réelle)

Prenez un moment pour tester la fonctionnalité de suppression. Il existe une clé étrangère entre la Products table s CategoryID et la Categories table s CategoryID. Vous obtiendrez donc une exception de violation de contrainte de clé étrangère si vous tentez de supprimer l’une des huit premières catégories. Pour tester cette fonctionnalité, ajoutez une nouvelle catégorie, en fournissant à la fois une brochure et une image. Ma catégorie de test, illustrée dans la figure 6, comprend un fichier de brochure de test nommé Test.pdf et une image de test. La figure 7 montre gridView après l’ajout de la catégorie de test.

Ajouter une catégorie de test avec une brochure et une image

Figure 6 : Ajouter une catégorie de test avec une brochure et une image (cliquer pour afficher une image en taille réelle)

Après l’insertion de la catégorie de test, elle s’affiche dans le GridView

Figure 7 : Après l’insertion de la catégorie de test, celle-ci s’affiche dans gridView (cliquez pour afficher l’image en taille réelle)

Dans Visual Studio, actualisez le Explorateur de solutions. Vous devez maintenant voir un nouveau fichier dans le ~/Brochures dossier ( Test.pdf voir la figure 8).

Cliquez ensuite sur le lien Supprimer dans la ligne Catégorie de test, ce qui entraîne la publication de la page et l’activation de la méthode de DeleteCategory classeCategoriesBLL. Cela appelle la méthode DAL, Delete ce qui entraîne l’envoi de l’instruction appropriée DELETE à la base de données. Les données sont ensuite renvoyées au GridView et le balisage est renvoyé au client avec la catégorie de test qui n’est plus présente.

Bien que le workflow de suppression ait correctement supprimé l’enregistrement catégorie de test de la Categories table, il n’a pas supprimé son fichier de brochure du système de fichiers du serveur web. Actualisez le Explorateur de solutions et vous verrez qu’il Test.pdf se trouve toujours dans le ~/Brochures dossier.

Le fichier Test.pdf n’a pas été supprimé du système de fichiers du serveur web

Figure 8 : Le Test.pdf fichier n’a pas été supprimé du système de fichiers du serveur web

Étape 5 : Suppression du fichier de brochure de catégorie supprimée

L’un des inconvénients du stockage de données binaires externes à la base de données est que des étapes supplémentaires doivent être prises pour propre ces fichiers lorsque l’enregistrement de base de données associé est supprimé. GridView et ObjectDataSource fournissent des événements qui se déclenchent avant et après l’exécution de la commande delete. En fait, nous devons créer des gestionnaires d’événements pour les événements avant et après l’action. Avant la suppression de l’enregistrement Categories , nous devons déterminer son chemin d’accès au fichier PDF, mais nous ne voulons pas supprimer le fichier PDF avant la suppression de la catégorie au cas où il y avait une exception et que la catégorie n’est pas supprimée.

L’événement GridView se RowDeleting déclenche avant l’appel de la commande De suppression d’ObjectDataSource, tandis que son RowDeleted événement se déclenche après. Créez des gestionnaires d’événements pour ces deux événements à l’aide du code suivant :

// A page variable to "remember" the deleted category's BrochurePath value 
string deletedCategorysPdfPath = null;
protected void Categories_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    // Determine the PDF path for the category being deleted...
    int categoryID = Convert.ToInt32(e.Keys["CategoryID"]);
    CategoriesBLL categoryAPI = new CategoriesBLL();
    Northwind.CategoriesDataTable categories = 
        categoryAPI.GetCategoryByCategoryID(categoryID);
    Northwind.CategoriesRow category = categories[0];
    if (category.IsBrochurePathNull())
        deletedCategorysPdfPath = null;
    else
        deletedCategorysPdfPath = category.BrochurePath;
}
protected void Categories_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
    // Delete the brochure file if there were no problems deleting the record
    if (e.Exception == null)
    {
        // Is there a file to delete?
        if (deletedCategorysPdfPath != null)
        {
            System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath));
        }
    }
}

Dans le RowDeleting gestionnaire d’événements, le CategoryID de la ligne en cours de suppression est saisi à partir de la collection GridView DataKeys , qui est accessible dans ce gestionnaire d’événements par le biais de la e.Keys collection. Ensuite, la CategoriesBLL classe s GetCategoryByCategoryID(categoryID) est appelée pour retourner des informations sur l’enregistrement en cours de suppression. Si l’objet retourné CategoriesDataRow a une valeur non-NULL``BrochurePath , il est stocké dans la variable deletedCategorysPdfPath de page afin que le fichier puisse être supprimé dans le RowDeleted gestionnaire d’événements.

Notes

Au lieu de récupérer les BrochurePath détails de l’enregistrement Categories en cours de suppression dans le RowDeleting gestionnaire d’événements, nous aurions pu ajouter le BrochurePath à la propriété gridView DataKeyNames et accéder à la valeur de l’enregistrement par le biais de la e.Keys collection. Cela augmenterait légèrement la taille de l’état d’affichage de GridView, mais réduirait la quantité de code nécessaire et économiserait un déplacement dans la base de données.

Une fois que la commande delete sous-jacente d’ObjectDataSource a été appelée, le gestionnaire d’événements de RowDeleted GridView se déclenche. S’il n’y avait aucune exception lors de la suppression des données et qu’il existe une valeur pour deletedCategorysPdfPath, le fichier PDF est supprimé du système de fichiers. Notez que ce code supplémentaire n’est pas nécessaire pour propre les données binaires de catégorie associées à son image. Cela est dû au fait que les données d’image sont stockées directement dans la base de données. La suppression de la Categories ligne supprime également les données d’image de cette catégorie.

Après avoir ajouté les deux gestionnaires d’événements, réexécutez ce cas de test. Lors de la suppression de la catégorie, son FICHIER PDF associé est également supprimé.

La mise à jour des données binaires associées à un enregistrement existant présente des défis intéressants. Le reste de ce tutoriel se penche sur l’ajout de fonctionnalités de mise à jour à la brochure et à l’image. L’étape 6 explore les techniques de mise à jour des informations de la brochure tandis que l’étape 7 examine la mise à jour de l’image.

Étape 6 : Mise à jour d’une brochure de catégorie

Comme indiqué dans le didacticiel Vue d’ensemble de l’insertion, de la mise à jour et de la suppression de données, GridView offre une prise en charge intégrée de l’édition au niveau des lignes qui peut être implémentée en cochant une case si sa source de données sous-jacente est correctement configurée. Actuellement, ObjectDataSource CategoriesDataSource n’étant pas encore configuré pour inclure la prise en charge de la mise à jour, nous allons l’ajouter dans.

Cliquez sur le lien Configurer la source de données à partir de l’Assistant ObjectDataSource et passez à la deuxième étape. En raison de la DataObjectMethodAttribute valeur utilisée dans CategoriesBLL, la liste déroulante UPDATE doit être automatiquement remplie avec la UpdateCategory surcharge qui accepte quatre paramètres d’entrée (pour toutes les colonnes sauf Picture). Modifiez ce paramètre afin qu’il utilise la surcharge avec cinq paramètres.

Configurer objectDataSource pour utiliser la méthode UpdateCategory qui inclut un paramètre pour Picture

Figure 9 : Configurer ObjectDataSource pour utiliser la UpdateCategory méthode qui inclut un paramètre pour Picture (Cliquez pour afficher l’image de taille réelle)

ObjectDataSource inclut désormais une valeur pour sa UpdateMethod propriété ainsi que les valeurs correspondantes UpdateParameter . Comme indiqué à l’étape 4, Visual Studio définit la propriété original_{0} ObjectDataSource sur lors de OldValuesParameterFormatString l’utilisation de l’Assistant Configuration de la source de données. Cela entraîne des problèmes avec les appels de méthode de mise à jour et de suppression. Par conséquent, effacez complètement cette propriété ou réinitialisez-la à la valeur par défaut, {0}.

Après avoir terminé l’Assistant et résolu le OldValuesParameterFormatString, le balisage déclaratif d’ObjectDataSource doit ressembler à ce qui suit :

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="{0}" SelectMethod="GetCategories" 
    TypeName="CategoriesBLL" InsertMethod="InsertWithPicture" 
    DeleteMethod="DeleteCategory" UpdateMethod="UpdateCategory">
    <InsertParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
    </InsertParameters>
    <DeleteParameters>
        <asp:Parameter Name="categoryID" Type="Int32" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="categoryName" Type="String" />
        <asp:Parameter Name="description" Type="String" />
        <asp:Parameter Name="brochurePath" Type="String" />
        <asp:Parameter Name="picture" Type="Object" />
        <asp:Parameter Name="categoryID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Pour activer les fonctionnalités d’édition intégrées de GridView, case activée l’option Activer la modification à partir de la balise active de GridView. Cette opération affecte à truela propriété CommandField la ShowEditButton valeur , ce qui entraîne l’ajout d’un bouton Modifier (et des boutons Mettre à jour et Annuler pour la ligne en cours de modification).

Configurer GridView pour prendre en charge la modification

Figure 10 : Configurer GridView pour prendre en charge la modification (cliquer pour afficher l’image en taille réelle)

Accédez à la page via un navigateur et cliquez sur l’un des boutons Modifier de la ligne. Les CategoryName champs Description et BoundField sont affichés sous forme de zones de texte. Le BrochurePath TemplateField n’a pas de EditItemTemplate, il continue donc d’afficher son ItemTemplate lien vers la brochure. L’ImageField Picture s’affiche sous la forme d’un TextBox dont Text la propriété est affectée à la valeur de l’ImageField, en l’occurrence DataImageUrlFieldCategoryID.

GridView ne dispose pas d’une interface d’édition pour BrochurePath

Figure 11 : GridView n’a pas d’interface d’édition pour BrochurePath (Cliquez pour afficher l’image en taille réelle)

Personnalisation de l’interfaceBrochurePathd’édition de s

Nous devons créer une interface d’édition pour templateField BrochurePath , qui permet à l’utilisateur de :

  • Laissez la brochure de catégorie telle qu’elle est,
  • Mettez à jour la brochure de catégorie en téléchargeant une nouvelle brochure, ou
  • Supprimez complètement la brochure de catégorie (dans le cas où la catégorie n’a plus de brochure associée).

Nous devons également mettre à jour l’interface Picture d’édition d’ImageField, mais nous allons y parvenir à l’étape 7.

Dans la balise active gridView, cliquez sur le lien Modifier les modèles et sélectionnez templateField BrochurePath dans EditItemTemplate la liste déroulante. Ajoutez un contrôle Web RadioButtonList à ce modèle, en définissant sa ID propriété sur BrochureOptions et sa AutoPostBack propriété sur true. À partir du Fenêtre Propriétés, cliquez sur les points de suspension dans la Items propriété, ce qui permet d’afficher le ListItem Rédacteur Collection. Ajoutez les trois options suivantes avec Value s 1, 2 et 3, respectivement :

  • Utiliser la brochure actuelle
  • Supprimer la brochure actuelle
  • Charger une nouvelle brochure

Définissez la première ListItem propriété truesur Selected .

Ajouter trois listItems à RadioButtonList

Figure 12 : Ajouter trois ListItem à RadioButtonList

Sous RadioButtonList, ajoutez un contrôle FileUpload nommé BrochureUpload. Définissez sa Visible propriété sur false.

Ajouter un contrôle RadioButtonList et FileUpload à l’objet EditItemTemplate

Figure 13 : Ajouter un contrôle RadioButtonList et FileUpload à (Cliquer pour afficher l’imageEditItemTemplate en taille réelle)

Ce RadioButtonList fournit les trois options pour l’utilisateur. L’idée est que le contrôle FileUpload s’affiche uniquement si la dernière option, Charger une nouvelle brochure, est sélectionnée. Pour ce faire, créez un gestionnaire d’événements pour l’événement RadioButtonList et SelectedIndexChanged ajoutez le code suivant :

protected void BrochureOptions_SelectedIndexChanged(object sender, EventArgs e)
{
    // Get a reference to the RadioButtonList and its Parent
    RadioButtonList BrochureOptions = (RadioButtonList)sender;
    Control parent = BrochureOptions.Parent;
    // Now use FindControl("controlID") to get a reference of the 
    // FileUpload control
    FileUpload BrochureUpload = 
        (FileUpload)parent.FindControl("BrochureUpload");
    // Only show BrochureUpload if SelectedValue = "3"
    BrochureUpload.Visible = (BrochureOptions.SelectedValue == "3");
}

Étant donné que les contrôles RadioButtonList et FileUpload se trouvent dans un modèle, nous devons écrire un peu de code pour accéder par programmation à ces contrôles. Le SelectedIndexChanged gestionnaire d’événements est passé une référence du RadioButtonList dans le paramètre d’entrée sender . Pour obtenir le contrôle FileUpload, nous devons obtenir le contrôle parent de RadioButtonList et utiliser la FindControl("controlID") méthode à partir de là. Une fois que nous avons une référence aux contrôles RadioButtonList et FileUpload, la propriété s du Visible contrôle FileUpload est définie sur uniquement si le RadioButtonList est SelectedValue égal à true 3, qui est le pour charger la Value nouvelle brochure ListItem.

Une fois ce code en place, prenez un moment pour tester l’interface d’édition. Cliquez sur le bouton Modifier pour une ligne. Au départ, l’option Utiliser la brochure actuelle doit être sélectionnée. La modification de l’index sélectionné entraîne une publication. Si la troisième option est sélectionnée, le contrôle FileUpload s’affiche, sinon il est masqué. La figure 14 montre l’interface d’édition lorsque l’utilisateur clique pour la première fois sur le bouton Modifier ; La figure 15 montre l’interface après l’sélection de l’option Charger une nouvelle brochure.

Initialement, l’option Utiliser la brochure actuelle est sélectionnée.

Figure 14 : Initialement, l’option Utiliser la brochure actuelle est sélectionnée (Cliquer pour afficher l’image en taille réelle)

Choisir l’option Charger une nouvelle brochure Affiche le contrôle FileUpload

Figure 15 : Choix de l’option Charger une nouvelle brochure Affiche le contrôle FileUpload (Cliquez pour afficher l’image en taille réelle)

Enregistrement du fichier de brochure et mise à jour de laBrochurePathcolonne

Lorsque vous cliquez sur le bouton Mettre à jour de GridView, son RowUpdating événement se déclenche. La commande de mise à jour d’ObjectDataSource est appelée, puis l’événement GridView se RowUpdated déclenche. Comme pour la suppression du flux de travail, nous devons créer des gestionnaires d’événements pour ces deux événements. Dans le RowUpdating gestionnaire d’événements, nous devons déterminer l’action à entreprendre en fonction SelectedValue du de RadioButtonList BrochureOptions :

  • Si a la SelectedValue valeur 1, nous voulons continuer à utiliser le même BrochurePath paramètre. Par conséquent, nous devons définir le paramètre ObjectDataSource brochurePath sur la valeur existante BrochurePath de l’enregistrement en cours de mise à jour. Le paramètre ObjectDataSource brochurePath peut être défini à l’aide de e.NewValues["brochurePath"] = value.
  • Si a la SelectedValue valeur 2, nous voulons définir la valeur de l’enregistrement BrochurePath sur NULL. Pour ce faire, définissez le paramètre ObjectDataSource brochurePath sur , ce qui entraîne l’utilisation d’une base de données NULL dans l’instruction UPDATE .Nothing S’il existe un fichier de brochure en cours de suppression, nous devons supprimer le fichier existant. Toutefois, nous ne voulons le faire que si la mise à jour se termine sans déclencher d’exception.
  • Si a la SelectedValue valeur 3, nous voulons nous assurer que l’utilisateur a chargé un fichier PDF, puis l’enregistrer dans le système de fichiers et mettre à jour la valeur de la colonne de l’enregistrement BrochurePath . En outre, s’il existe un fichier de brochure existant qui est remplacé, nous devons supprimer le fichier précédent. Toutefois, nous ne voulons le faire que si la mise à jour se termine sans déclencher d’exception.

Les étapes qui devaient être effectuées lorsque radioButtonList a SelectedValue la valeur 3 sont pratiquement identiques à celles utilisées par le gestionnaire d’événements DetailsView ItemInserting . Ce gestionnaire d’événements est exécuté lorsqu’un nouvel enregistrement de catégorie est ajouté à partir du contrôle DetailsView que nous avons ajouté dans le didacticiel précédent. Par conséquent, il nous incombe de refactoriser cette fonctionnalité dans des méthodes distinctes. Plus précisément, j’ai déplacé la fonctionnalité commune dans deux méthodes :

  • ProcessBrochureUpload(FileUpload, out bool)accepte comme entrée un contrôle FileUpload instance et une valeur booléenne de sortie qui spécifie si l’opération de suppression ou de modification doit se poursuivre ou si elle doit être annulée en raison d’une erreur de validation. Cette méthode retourne le chemin d’accès au fichier enregistré ou null si aucun fichier n’a été enregistré.
  • DeleteRememberedBrochurePath supprime le fichier spécifié par le chemin d’accès dans la variable deletedCategorysPdfPath de page si deletedCategorysPdfPath n’est pas null.

Le code de ces deux méthodes est le suivant. Notez la similitude entre ProcessBrochureUpload et le gestionnaire d’événements ItemInserting DetailsView du tutoriel précédent. Dans ce tutoriel, j’ai mis à jour les gestionnaires d’événements de DetailsView pour utiliser ces nouvelles méthodes. Téléchargez le code associé à ce didacticiel pour voir les modifications apportées aux gestionnaires d’événements DetailsView.

private string ProcessBrochureUpload
    (FileUpload BrochureUpload, out bool CancelOperation)
{
    CancelOperation = false;    // by default, do not cancel operation
    if (BrochureUpload.HasFile)
    {
        // Make sure that a PDF has been uploaded
        if (string.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName), 
            ".pdf", true) != 0)
        {
            UploadWarning.Text = 
                "Only PDF documents may be used for a category's brochure.";
            UploadWarning.Visible = true;
            CancelOperation = true;
            return null;
        }
        const string BrochureDirectory = "~/Brochures/";
        string brochurePath = BrochureDirectory + BrochureUpload.FileName;
        string fileNameWithoutExtension = 
            System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
        int iteration = 1;
        while (System.IO.File.Exists(Server.MapPath(brochurePath)))
        {
            brochurePath = string.Concat(BrochureDirectory, fileNameWithoutExtension, 
                "-", iteration, ".pdf");
            iteration++;
        }
        // Save the file to disk and set the value of the brochurePath parameter
        BrochureUpload.SaveAs(Server.MapPath(brochurePath));
        return brochurePath;
    }
    else
    {
        // No file uploaded
        return null;
    }
}
private void DeleteRememberedBrochurePath()
{
    // Is there a file to delete?
    if (deletedCategorysPdfPath != null)
    {
        System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath));
    }
}

Les gestionnaires d’événements et gridView RowUpdating utilisent les ProcessBrochureUpload méthodes et DeleteRememberedBrochurePath , comme le montre le code RowUpdated suivant :

protected void Categories_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    // Reference the RadioButtonList
    RadioButtonList BrochureOptions = 
        (RadioButtonList)Categories.Rows[e.RowIndex].FindControl("BrochureOptions");
    // Get BrochurePath information about the record being updated
    int categoryID = Convert.ToInt32(e.Keys["CategoryID"]);
    CategoriesBLL categoryAPI = new CategoriesBLL();
    Northwind.CategoriesDataTable categories = 
        categoryAPI.GetCategoryByCategoryID(categoryID);
    Northwind.CategoriesRow category = categories[0];
    if (BrochureOptions.SelectedValue == "1")
    {
        // Use current value for BrochurePath
        if (category.IsBrochurePathNull())
            e.NewValues["brochurePath"] = null;
        else
            e.NewValues["brochurePath"] = category.BrochurePath;
    }
    else if (BrochureOptions.SelectedValue == "2")
    {
        // Remove the current brochure (set it to NULL in the database)
        e.NewValues["brochurePath"] = null;
    }
    else if (BrochureOptions.SelectedValue == "3")
    {
        // Reference the BrochurePath FileUpload control
        FileUpload BrochureUpload = 
            (FileUpload)Categories.Rows[e.RowIndex].FindControl("BrochureUpload");
        // Process the BrochureUpload
        bool cancelOperation = false;
        e.NewValues["brochurePath"] = 
            ProcessBrochureUpload(BrochureUpload, out cancelOperation);
        e.Cancel = cancelOperation;
    }
    else
    {
        // Unknown value!
        throw new ApplicationException(
            string.Format("Invalid BrochureOptions value, {0}", 
                BrochureOptions.SelectedValue));
    }
    if (BrochureOptions.SelectedValue == "2" || 
        BrochureOptions.SelectedValue == "3")
    {
        // "Remember" that we need to delete the old PDF file
        if (category.IsBrochurePathNull())
            deletedCategorysPdfPath = null;
        else
            deletedCategorysPdfPath = category.BrochurePath;
    }
}
protected void Categories_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
    // If there were no problems and we updated the PDF file, 
    // then delete the existing one
    if (e.Exception == null)
    {
        DeleteRememberedBrochurePath();
    }
}

Notez comment le RowUpdating gestionnaire d’événements utilise une série d’instructions conditionnelles pour effectuer l’action appropriée en fonction de la valeur de propriété BrochureOptions de SelectedValue RadioButtonList.

Une fois ce code en place, vous pouvez modifier une catégorie et lui faire utiliser sa brochure actuelle, n’utiliser aucune brochure ou en télécharger une nouvelle. Allez-y et essayez-le. Définissez des points d’arrêt dans les RowUpdating gestionnaires d’événements et RowUpdated pour avoir une idée du flux de travail.

Étape 7 : Chargement d’une nouvelle image

L’interface Picture d’édition d’ImageField s’affiche sous la forme d’une zone de texte remplie avec la valeur de sa DataImageUrlField propriété. Pendant le flux de travail d’édition, GridView transmet un paramètre à ObjectDataSource avec le nom du paramètre la valeur de la propriété ImageField DataImageUrlField et la valeur du paramètre s la valeur entrée dans la zone de texte dans l’interface d’édition. Ce comportement convient lorsque l’image est enregistrée en tant que fichier sur le système de fichiers et que contient DataImageUrlField l’URL complète de l’image. Dans de telles circonstances, l’interface d’édition affiche l’URL de l’image dans la zone de texte, que l’utilisateur peut modifier et avoir enregistrée dans la base de données. Certes, cette interface par défaut ne permet pas à l’utilisateur de charger une nouvelle image, mais elle lui permet de modifier l’URL de l’image de la valeur actuelle en une autre. Toutefois, pour ce tutoriel, l’interface d’édition par défaut d’ImageField ne suffit pas, car les Picture données binaires sont stockées directement dans la base de données et la DataImageUrlField propriété contient uniquement le CategoryID.

Pour mieux comprendre ce qui se passe dans notre tutoriel lorsqu’un utilisateur modifie une ligne avec un champ ImageField, prenons l’exemple suivant : un utilisateur modifie une ligne avec CategoryID 10, ce qui entraîne le rendu de l’ImageField Picture sous la forme d’une zone de texte avec la valeur 10. Imaginez que l’utilisateur remplace la valeur de cette zone de texte par 50 et clique sur le bouton Mettre à jour. Une publication se produit et gridView crée initialement un paramètre nommé CategoryID avec la valeur 50. Toutefois, avant que GridView n’envoie ce paramètre (et les CategoryName paramètres et Description ), il ajoute les valeurs de la DataKeys collection. Par conséquent, il remplace le CategoryID paramètre par la valeur sous-jacente CategoryID de la ligne actuelle, 10. En bref, l’interface d’édition d’ImageField n’a aucun impact sur le flux de travail d’édition de ce didacticiel, car les noms de la propriété ImageField DataImageUrlField et de la valeur de la grille sont DataKey identiques.

Bien que l’objet ImageField facilite l’affichage d’une image basée sur des données de base de données, nous ne voulons pas fournir de zone de texte dans l’interface d’édition. Nous voulons plutôt offrir un contrôle FileUpload que l’utilisateur final peut utiliser pour modifier l’image de catégorie. Contrairement à la BrochurePath valeur, pour ces tutoriels, nous avons décidé d’exiger que chaque catégorie ait une image. Par conséquent, nous n’avons pas besoin de laisser l’utilisateur indiquer qu’aucune image n’est associée, l’utilisateur peut soit charger une nouvelle image, soit laisser l’image actuelle telle quelle.

Pour personnaliser l’interface d’édition d’ImageField, nous devons la convertir en TemplateField. À partir de la balise active gridView, cliquez sur le lien Modifier les colonnes, sélectionnez imageField, puis cliquez sur le lien Convertir ce champ en un champ TemplateField.

Convertir l’ImageField en templateField

Figure 16 : Convertir l’imageField en champ de modèle

La conversion de l’ImageField en templateField de cette manière génère un TemplateField avec deux modèles. Comme le montre la syntaxe déclarative suivante, contient un contrôle Image Web dont la ItemTemplate propriété est affectée à l’aide de la syntaxe de DataImageUrlField liaison de données basée sur les propriétés ImageField et DataImageUrlFormatString .ImageUrl contient EditItemTemplate une zone de texte dont Text la propriété est liée à la valeur spécifiée par la DataImageUrlField propriété .

<asp:TemplateField>
    <EditItemTemplate>
        <asp:TextBox ID="TextBox1" runat="server" 
            Text='<%# Eval("CategoryID") %>'></asp:TextBox>
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Image ID="Image1" runat="server" 
            ImageUrl='<%# Eval("CategoryID", 
                "DisplayCategoryPicture.aspx?CategoryID={0}") %>' />
    </ItemTemplate>
</asp:TemplateField>

Nous devons mettre à jour pour EditItemTemplate utiliser un contrôle FileUpload. Dans la balise active de GridView, cliquez sur le lien Modifier les modèles, puis sélectionnez templateField Picture dans EditItemTemplate la liste déroulante. Dans le modèle, vous devriez voir une zone de texte supprimer ce. Ensuite, faites glisser un contrôle FileUpload de la boîte à outils dans le modèle, en affectant ID la valeur à PictureUpload. Ajoutez également le texte Pour modifier l’image de catégorie, spécifiez une nouvelle image. Pour conserver l’image de catégorie identique, laissez également le champ vide dans le modèle.

Ajouter un contrôle FileUpload à l’objet EditItemTemplate

Figure 17 : Ajouter un contrôle FileUpload à (EditItemTemplateCliquer pour afficher l’image en taille réelle)

Après avoir personnalisé l’interface d’édition, affichez votre progression dans un navigateur. Lors de l’affichage d’une ligne en mode lecture seule, l’image de catégorie s’affiche telle qu’elle était auparavant, mais le fait de cliquer sur le bouton Modifier restitue la colonne d’image en tant que texte avec un contrôle FileUpload.

L’interface d’édition inclut un contrôle FileUpload

Figure 18 : L’interface d’édition inclut un contrôle FileUpload (cliquer pour afficher l’image en taille réelle)

Rappelez-vous que ObjectDataSource est configuré pour appeler la CategoriesBLL méthode de classe s UpdateCategory qui accepte comme entrée les données binaires de l’image sous forme de byte tableau. Toutefois, si ce tableau a une null valeur, l’autre UpdateCategory surcharge est appelée, ce qui émet l’instruction UPDATE SQL qui ne modifie pas la Picture colonne, laissant ainsi l’image actuelle de la catégorie intacte. Par conséquent, dans le gestionnaire d’événements gridView, RowUpdating nous devons référencer par programmation le PictureUpload contrôle FileUpload et déterminer si un fichier a été chargé. Si l’un d’eux n’a pas été chargé, nous ne voulons pas spécifier de valeur pour le picture paramètre . En revanche, si un fichier a été chargé dans le PictureUpload contrôle FileUpload, nous voulons nous assurer qu’il s’agit d’un fichier JPG. Si c’est le cas, nous pouvons envoyer son contenu binaire à ObjectDataSource via le picture paramètre .

Comme avec le code utilisé à l’étape 6, une grande partie du code nécessaire existe déjà dans le gestionnaire d’événements DetailsView ItemInserting . Par conséquent, j’ai refactorisé la fonctionnalité commune dans une nouvelle méthode, ValidPictureUpload, et mis à jour le ItemInserting gestionnaire d’événements pour utiliser cette méthode.

Ajoutez le code suivant au début du gestionnaire d’événements GridView RowUpdating . Il est important que ce code précède le code qui enregistre le fichier de brochure, car nous ne voulons pas enregistrer la brochure dans le système de fichiers du serveur web si un fichier image non valide est chargé.

// Reference the PictureUpload FileUpload
FileUpload PictureUpload = 
    (FileUpload)Categories.Rows[e.RowIndex].FindControl("PictureUpload");
if (PictureUpload.HasFile)
{
    // Make sure the picture upload is valid
    if (ValidPictureUpload(PictureUpload))
    {
        e.NewValues["picture"] = PictureUpload.FileBytes;
    }
    else
    {
        // Invalid file upload, cancel update and exit event handler
        e.Cancel = true;
        return;
    }
}

La ValidPictureUpload(FileUpload) méthode prend un contrôle FileUpload comme seul paramètre d’entrée et vérifie l’extension du fichier chargé pour s’assurer que le fichier chargé est un fichier JPG ; il est appelé uniquement si un fichier image est chargé. Si aucun fichier n’est chargé, le paramètre picture n’est pas défini et utilise donc sa valeur par défaut .null Si une image a été chargée et ValidPictureUpload retourne , les picture données binaires de l’image chargée sont affectées au paramètre ; si la méthode retourne false, le flux de travail de mise à jour est annulé et le gestionnaire d’événements trueest arrêté.

Le ValidPictureUpload(FileUpload) code de méthode, qui a été refactorisé à partir du gestionnaire d’événements DetailsView ItemInserting , suit :

private bool ValidPictureUpload(FileUpload PictureUpload)
{
    // Make sure that a JPG has been uploaded
    if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
            ".jpg", true) != 0 &&
        string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
            ".jpeg", true) != 0)
    {
        UploadWarning.Text = 
            "Only JPG documents may be used for a category's picture.";
        UploadWarning.Visible = true;
        return false;
    }
    else
    {
        return true;
    }
}

Étape 8 : Remplacement des images de catégories d’origine par des images jpg

Rappelez-vous que les huit images de catégories d’origine sont des fichiers bitmap encapsulés dans un en-tête OLE. Maintenant que nous avons ajouté la possibilité de modifier une image d’enregistrement existante, prenez un moment pour remplacer ces bitmaps par des JPG. Si vous souhaitez continuer à utiliser les images de catégorie actuelle, vous pouvez les convertir en JPG en procédant comme suit :

  1. Enregistrez les images bitmap sur votre disque dur. Visitez la UpdatingAndDeleting.aspx page dans votre navigateur et, pour chacune des huit premières catégories, cliquez avec le bouton droit sur l’image et choisissez d’enregistrer l’image.
  2. Ouvrez l’image dans l’éditeur d’images de votre choix. Vous pouvez utiliser Microsoft Paint, par exemple.
  3. Enregistrez la bitmap en tant qu’image JPG.
  4. Mettez à jour l’image de la catégorie via l’interface d’édition, à l’aide du fichier JPG.

Après avoir modifié une catégorie et téléchargé l’image JPG, l’image ne s’affiche pas dans le navigateur, car la DisplayCategoryPicture.aspx page supprime les 78 premiers octets des images des huit premières catégories. Corrigez ce problème en supprimant le code qui effectue le retrait de l’en-tête OLE. Après cela, le DisplayCategoryPicture.aspx``Page_Load gestionnaire d’événements doit avoir uniquement le code suivant :

protected void Page_Load(object sender, EventArgs e)
{
    int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]);
    // Get information about the specified category
    CategoriesBLL categoryAPI = new CategoriesBLL();
    Northwind.CategoriesDataTable categories = _
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID);
    Northwind.CategoriesRow category = categories[0];
    // For new categories, images are JPGs...
    
    // Output HTTP headers providing information about the binary data
    Response.ContentType = "image/jpeg";
    // Output the binary data
    Response.BinaryWrite(category.Picture);
}

Notes

Les UpdatingAndDeleting.aspx interfaces d’insertion et de modification des pages peuvent utiliser un peu plus de travail. Les CategoryName champs Description et boundfields dans DetailsView et GridView doivent être convertis en TemplateFields. Étant donné CategoryName que n’autorise NULL pas les valeurs, un RequiredFieldValidator doit être ajouté. Et la Description zone de texte doit probablement être convertie en une zone de texte multiligne. Je laisse ces touches finales comme un exercice pour vous.

Résumé

Ce tutoriel complète notre présentation de l’utilisation de données binaires. Dans ce tutoriel et les trois précédents, nous avons vu comment les données binaires peuvent être stockées sur le système de fichiers ou directement dans la base de données. Un utilisateur fournit des données binaires au système en sélectionnant un fichier à partir de son disque dur et en le chargeant sur le serveur web, où il peut être stocké sur le système de fichiers ou inséré dans la base de données. ASP.NET 2.0 inclut un contrôle FileUpload qui facilite la fourniture d’une telle interface par glisser-déplacer. Toutefois, comme indiqué dans le tutoriel Chargement de fichiers , le contrôle FileUpload est uniquement adapté aux chargements de fichiers relativement petits, idéalement ne dépassant pas un mégaoctet. Nous avons également exploré comment associer des données chargées au modèle de données sous-jacent, ainsi que comment modifier et supprimer les données binaires des enregistrements existants.

Notre prochain ensemble de tutoriels explore différentes techniques de mise en cache. La mise en cache permet d’améliorer les performances globales d’une application en prenant les résultats des opérations coûteuses et en les stockant dans un emplacement accessible plus rapidement.

Bonne programmation !

À propos de l’auteur

Scott Mitchell, auteur de sept livres ASP/ASP.NET et fondateur de 4GuysFromRolla.com, travaille avec les technologies Web Microsoft depuis 1998. Scott travaille comme consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 2.0 in 24 Heures. Il est accessible à l’adressemitchell@4GuysFromRolla.com . ou via son blog, qui peut être trouvé à l’adresse http://ScottOnWriting.NET.

Un merci spécial à

Cette série de tutoriels a été examinée par de nombreux réviseurs utiles. La réviseur principale de ce tutoriel était Teresa Murphy. Vous souhaitez consulter mes prochains articles MSDN ? Si c’est le cas, déposez-moi une ligne à mitchell@4GuysFromRolla.com.