Partager via


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

par Scott Mitchell

Télécharger le PDF

Dans les didacticiels précédents, nous avons vu comment le contrôle GridView facilite la modification et la suppression de 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.

Présentation

Au cours des trois derniers didacticiels, nous avons ajouté un peu de fonctionnalités pour l’utilisation de 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 de couche d’accès aux données et de couche logique métier pour travailler avec la colonne existante Picture de la table Categories, qui contient les contenus binaires d’un fichier image. Nous avons créé des pages web pour présenter les données binaires dans un GridView et un lien de téléchargement pour la brochure, avec l'image de la catégorie affichée dans un élément <img>. Nous avons également ajouté un DetailsView pour permettre aux utilisateurs d'ajouter une nouvelle catégorie et de télécharger les données de sa brochure et de son image.

Tout ce qui reste à implémenter est la possibilité de modifier et de supprimer des catégories existantes, que nous allons accomplir dans ce tutoriel à l’aide des fonctionnalités intégrées d’édition et de suppression de GridView. Lors de la modification d’une catégorie, l’utilisateur peut éventuellement charger une nouvelle image ou continuer à utiliser la catégorie existante. Pour la brochure, ils peuvent choisir d’utiliser la brochure existante, de 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é automatiquement les méthodes Insert, Update et Delete, mais ces méthodes ont été générées en fonction de la requête principale CategoriesTableAdapter, qui n'inclut pas la colonne Picture. Par conséquent, les méthodes Insert et Update n’incluent pas de paramètres pour spécifier les données binaires de l’image de catégorie. Comme nous l’avons fait dans le tutoriel précédent, nous devons créer une méthode TableAdapter pour mettre à jour la table lors de la Categories spécification de données binaires.

Ouvrez le jeu de données typé et, dans le concepteur, cliquez avec le bouton droit sur l’en-tête CategoriesTableAdapter et choisissez Ajouter une requête dans le menu contextuel pour lancer l'assistant de 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 demande de préciser le type de requête à générer. Étant donné que nous créons une requête pour ajouter un nouvel enregistrement à la Categories table, choisissez UPDATE, puis cliquez sur Suivant.

Sélectionner l’option UPDATE

Figure 1 : Sélectionner l’option UPDATE (cliquez pour afficher l’image de taille complète)

Nous devons maintenant spécifier l’instruction UPDATE SQL. L’Assistant suggère automatiquement une instruction UPDATE correspondant à la requête principale de TableAdapter (une instruction qui met à jour les valeurs CategoryName, Description et 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))

L’écran final de l’Assistant nous invite à nommer la nouvelle méthode TableAdapter. Entrez UpdateWithPicture et cliquez sur Terminer.

Nommez la nouvelle méthode TableAdapter UpdateWithPicture

Figure 2 : Nommer la méthode New TableAdapter UpdateWithPicture (Cliquez pour voir 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 afin d’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 présentation.

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

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Delete, True)> _
Public Function DeleteCategory(ByVal categoryID As Integer) As Boolean
    Dim rowsAffected As Integer = Adapter.Delete(categoryID)
    ' Return true if precisely one row was deleted, otherwise false
    Return rowsAffected = 1
End Function

Pour ce didacticiel, nous allons créer deux méthodes pour mettre à jour une catégorie : l'une qui attend les données d'image binaire et invoque la méthode UpdateWithPicture que nous venons d'ajouter à la méthode CategoriesTableAdapter, et une autre qui accepte uniquement les valeurs CategoryName, Description et BrochurePath et utilise l'instruction générée automatiquement par la classe CategoriesTableAdapter de la classe Update. 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 la catégorie avec ses autres champs, auquel cas l’utilisateur devra charger la nouvelle image. Les données binaires de l’image chargée peuvent ensuite être utilisées dans l’instruction UPDATE . Dans d'autres cas, l'utilisateur peut être seulement intéressé par la mise à jour du nom et de la description, par exemple. Toutefois, si l’instruction UPDATE attend également les données binaires de la Picture colonne, nous devons également fournir ces informations. Cela nécessiterait un voyage supplémentaire vers 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éterminera laquelle utiliser en fonction de la fourniture des données d'image lors de la mise à jour de la catégorie.

Pour faciliter cette opération, ajoutez deux méthodes à la CategoriesBLL classe, toutes deux nommées UpdateCategory. Le premier doit accepter trois String s, un Byte tableau et un Integer comme paramètres d’entrée ; le second, juste trois String s et un Integer. Les paramètres d’entrée String servent pour le nom, la description et le chemin du fichier de brochure de la catégorie. Le tableau Byte correspond aux contenus binaires de l’image de la catégorie, et Integer identifie l’élément CategoryID de l’enregistrement à mettre à jour. Notez que la première surcharge appelle la seconde si le tableau transmis en entrée Byte est Nothing:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, False)> _
Public Function UpdateCategory(categoryName As String, description As String, _
    brochurePath As String, picture() As Byte, categoryID As Integer) As Boolean
    
    ' If no picture is specified, use other overload
    If picture Is Nothing Then
        Return UpdateCategory(categoryName, description, brochurePath, categoryID)
    End If
    ' Update picture, as well
    Dim rowsAffected As Integer = Adapter.UpdateWithPicture _
        (categoryName, description, brochurePath, picture, categoryID)
    ' Return true if precisely one row was updated, otherwise false
    Return rowsAffected = 1
End Function
<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateCategory(categoryName As String, description As String, _
    brochurePath As String, categoryID As Integer) As Boolean
    Dim rowsAffected As Integer = Adapter.Update _
        (categoryName, description, brochurePath, categoryID)
    ' Return true if precisely one row was updated, otherwise false
    Return rowsAffected = 1
End Function

Étape 3 : Copier la fonctionnalité 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 fourni un DetailsView pour ajouter de nouvelles catégories au système. Dans ce tutoriel, nous allons étendre GridView pour inclure les fonctionnalités de modification et de suppression. Au lieu de continuer à travailler à partir de UploadInDetailsView.aspx, nous allons plutôt placer les modifications de ce tutoriel dans la UpdatingAndDeleting.aspx page à partir du même dossier, ~/BinaryData. Copiez et collez le balisage déclaratif et le code de UploadInDetailsView.aspx vers UpdatingAndDeleting.aspx.

Commencez par ouvrir la UploadInDetailsView.aspx page. Copiez l’ensemble de la syntaxe déclarative dans l’élément, comme illustré dans la <asp:Content> 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 page UploadInDetailsView.aspx vers UpdatingAndDeleting.aspx.

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

Figure 3 : Copier le balisage déclaratif à partir de UploadInDetailsView.aspx (cliquez pour afficher l’image de taille complète)

Après avoir copié le balisage déclaratif et le code, visitez UpdatingAndDeleting.aspx. Vous devez voir la même sortie et avoir la même expérience utilisateur que la UploadInDetailsView.aspx page du didacticiel 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 des données, GridView fournit des fonctionnalités de suppression intégrées et ces fonctionnalités peuvent être activées à la coche d’une case si la source de données sous-jacente de la grille prend en charge la suppression. Actuellement, ObjectDataSource auquel GridView est lié (CategoriesDataSource) ne prend pas en charge la suppression.

Pour résoudre ce problème, cliquez sur l’option Configurer la source de données à partir du smart tag 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 InsertMethod et SelectMethod d'ObjectDataSource sont spécifiées. Toutefois, l’Assistant a automatiquement renseigné les listes déroulantes dans les onglets UPDATE et DELETE avec les méthodes UpdateCategory et DeleteCategory, respectivement. Cela est dû au fait que dans la CategoriesBLL classe, nous avons marqué ces méthodes en utilisant les DataObjectMethodAttribute comme les méthodes par défaut pour la mise à jour et la suppression.

Pour l'instant, définissez la liste déroulante de l'onglet UPDATE sur (Aucun), mais laissez la liste déroulante de l'onglet DELETE définie sur DeleteCategory. Nous allons revenir à 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 méthode (DeleteCategory de taille complète)

Remarque

Une fois l’Assistant terminé, Visual Studio peut vous demander si vous souhaitez actualiser les champs et les clés, afin de régénérer les champs des contrôles Web de données. Choisissez Non, car le choix oui remplacera les personnalisations de champ que vous avez peut-être effectuées.

ObjectDataSource inclut désormais une valeur pour sa DeleteMethod propriété ainsi qu’un DeleteParameter. Rappelez-vous que lors de l’utilisation de l’Assistant pour spécifier les méthodes, Visual Studio définit la propriété OldValuesParameterFormatStringObjectDataSourceoriginal_{0} 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 sur 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 .

Une fois l’Assistant terminé et après correction de OldValuesParameterFormatString, le balisage déclaratif de ObjectDataSource devrait être similaire à 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é l'ObjectDataSource, ajoutez des fonctionnalités de suppression à GridView en cochant la case Activer la suppression depuis la balise intelligente de GridView. Cela ajoutera un CommandField à le GridView dont la propriété ShowDeleteButton 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 (cliquez pour afficher l’image de taille complète)

Prenez un moment pour tester la fonctionnalité de suppression. Il existe une clé étrangère entre les tables Products s CategoryID et Categories s CategoryID, donc vous obtiendrez 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, fournissant à la fois une brochure et une image. Ma catégorie de test, illustrée à la figure 6, inclut 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 (cliquez pour afficher l’image de taille complète)

Après avoir inséré la catégorie de test, elle est affichée dans GridView

Figure 7 : Après l’insertion de la catégorie de test, elle est affichée dans GridView (cliquez pour afficher l’image de taille complète)

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

Ensuite, cliquez sur le lien Supprimer dans la ligne Catégorie de test, entraînant un rafraîchissement de la page et la méthode de la classe CategoriesBLLDeleteCategory à s'exécuter. 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 réinjectées dans GridView et le code HTML est renvoyé au client sans la catégorie de test.

Bien que le flux de travail de suppression ait correctement supprimé l’enregistrement de la 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 l’Explorateur de solutions et vous verrez que Test.pdf se trouve toujours dans le ~/Brochures répertoire.

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 la 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 effectuées pour nettoyer 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. Nous devons en fait créer des gestionnaires d’événements pour les événements de pré-action et de post-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 que la catégorie soit supprimée en cas d’exception et que la catégorie ne soit pas supprimée.

L'événement de GridView se déclenche avant que la commande de suppression d'ObjectDataSource ait été appelée, tandis que son é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
Private deletedCategorysPdfPath As String = Nothing
Protected Sub Categories_RowDeleting(sender As Object, e As GridViewDeleteEventArgs) _
    Handles Categories.RowDeleting
    
    ' Determine the PDF path for the category being deleted...
    Dim categoryID As Integer = Convert.ToInt32(e.Keys("CategoryID"))
    Dim categoryAPI As New CategoriesBLL()
    Dim categoriesData As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = categoriesData(0)
    If category.IsBrochurePathNull() Then
        deletedCategorysPdfPath = Nothing
    Else
        deletedCategorysPdfPath = category.BrochurePath
    End If
End Sub
Protected Sub Categories_RowDeleted(sender As Object, e As GridViewDeletedEventArgs) _
    Handles Categories.RowDeleted
    
    ' Delete the brochure file if there were no problems deleting the record
    If e.Exception Is Nothing Then
        DeleteRememberedBrochurePath()
    End If
End Sub

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

Remarque

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 également ajouter l’BrochurePath à la propriété DataKeyNames de GridView et accéder à la valeur de l’enregistrement par le biais de la collection e.Keys. Cela augmenterait légèrement la taille de l'état de vue de GridView, mais réduirait la quantité de code nécessaire et éviterait une requête à la base de données.

Une fois la commande de suppression sous-jacente ObjectDataSource appelée, le gestionnaire d’événements RowDeleted GridView se déclenche. S’il n’y avait aucune exception lors de la suppression des données et qu’il y a une valeur, deletedCategorysPdfPathle fichier PDF est supprimé du système de fichiers. Notez que ce code supplémentaire n’est pas nécessaire pour nettoyer les données binaires de la 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, de sorte que 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 constitue des défis intéressants. Le reste de ce tutoriel explique comment ajouter des fonctionnalités de mise à jour à la brochure et à l’image. L’étape 6 explore les techniques de mise à jour des informations de brochure pendant 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 des données, GridView offre une prise en charge intégrée de l’édition au niveau des lignes qui peut être implémentée par la coche d’une case si sa source de données sous-jacente est correctement configurée. Actuellement, CategoriesDataSource ObjectDataSource n’est pas encore configuré pour inclure la prise en charge de la mise à jour. Nous allons donc l’ajouter.

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

Configurer ObjectDataSource pour utiliser la méthode UpdateCategory qui inclut un paramètre pour l’image

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

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é de OldValuesParameterFormatString ObjectDataSource original_{0} lorsque vous utilisez l’Assistant Configurer 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 sur la valeur par défaut. {0}

Une fois l’Assistant terminé et que OldValuesParameterFormatString est corrigé, le balisage déclaratif 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, cochez l’option Activer la modification à partir de la balise active gridView. Cela définit la propriété ShowEditButton de CommandField sur True, ce qui entraîne l’ajout d’un bouton Modifier (et des boutons Mettre à jour et Annuler pour la ligne actuellement éditée).

Configurer GridView pour prendre en charge la modification

Figure 10 : Configurer GridView pour prendre en charge la modification (cliquez pour afficher l’image de taille complète)

Visitez la page en utilisant un navigateur et cliquez sur l'un des boutons "Modifier" d'une ligne. Les CategoryName et Description BoundFields sont rendues sous forme de zones de texte. Le BrochurePath TemplateField ne dispose pas d’un EditItemTemplate, il continue donc à montrer son ItemTemplate lien vers la brochure. ImageField Picture s'affiche sous la forme d'un TextBox dont la propriété Text est assignée à la valeur de l'ImageField DataImageUrlField, dans ce cas CategoryID.

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

Figure 11 : GridView ne dispose pas d’une interface d’édition pour BrochurePath (cliquez pour afficher l’image de taille complète)

Personnalisation de l’interfaceBrochurePathd’édition

Nous devons créer une interface d’édition pour TemplateField BrochurePath , qui permet à l’utilisateur d’effectuer les opérations suivantes :

  • Veuillez laisser la brochure de la catégorie as-is.
  • Mettez à jour la brochure de catégorie en 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 y accéderons à l’étape 7.

Dans la balise active gridView, cliquez sur le lien Modifier les modèles et sélectionnez TemplateField BrochurePath s EditItemTemplate dans la liste déroulante. Ajoutez un contrôle Web RadioButtonList à ce modèle, en définissant sa propriété ID sur BrochureOptions et sa propriété AutoPostBack sur True. Dans la fenêtre Propriétés, cliquez sur les points de suspension dans la Items propriété, ce qui affiche l'Éditeur de Collection ListItem. Ajoutez les trois options suivantes avec Value 1, 2 et 3, respectivement :

  • Utiliser la brochure actuelle
  • Supprimer la brochure actuelle
  • Télécharger une nouvelle brochure

Définissez la première propriété ListItem à SelectedTrue.

Ajouter trois éléments de liste à la liste de boutons radio

Figure 12 : Ajouter trois ListItem s à RadioButtonList

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

Ajouter un contrôle RadioButtonList et FileUpload à EditItemTemplate

Figure 13 : Ajouter un contrôle RadioButtonList et FileUpload à l’écran EditItemTemplate (Cliquez pour afficher l’image de taille complète)

Cette RadioButtonList fournit les trois options pour l’utilisateur. L’idée est que le contrôle FileUpload ne s’affiche que 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 SelectedIndexChanged et ajoutez le code suivant :

Protected Sub BrochureOptions_SelectedIndexChanged _
    (sender As Object, e As EventArgs)
    
    ' Get a reference to the RadioButtonList and its Parent
    Dim BrochureOptions As RadioButtonList = _
        CType(sender, RadioButtonList)
    Dim parent As Control = BrochureOptions.Parent
    ' Now use FindControl("controlID") to get a reference of the 
    ' FileUpload control
    Dim BrochureUpload As FileUpload = _
        CType(parent.FindControl("BrochureUpload"), FileUpload)
    ' Only show BrochureUpload if SelectedValue = "3"
    BrochureUpload.Visible = (BrochureOptions.SelectedValue = "3")
End Sub

É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 gestionnaire d’événements SelectedIndexChanged reçoit une référence de la 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é du contrôle FileUpload est définie à Visible uniquement si la valeur de True RadioButtonList est égale à 3, qui est l'option pour l'Upload de la nouvelle brochure SelectedValue.

Avec 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é provoque un retour de post. 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 le bouton Modifier est cliqué pour la première fois ; La figure 15 montre l’interface une fois que l’option Charger une nouvelle brochure est sélectionnée.

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

Figure 14 : Initialement, l’option Utiliser la brochure actuelle est sélectionnée (Cliquez pour afficher l’image de taille complète)

Le choix de l’option Charger une nouvelle brochure affiche le contrôle FileUpload

Figure 15 : Choisir l’option Charger une nouvelle brochure affiche le contrôle FileUpload (Cliquez pour afficher l’image de taille complète)

Enregistrement du fichier de brochure et mise à jour de laBrochurePathcolonne

Lorsque le bouton Mettre à jour de GridView est cliqué, son RowUpdating événement se déclenche. La commande de mise à jour ObjectDataSource est appelée, puis l’événement RowUpdated GridView se déclenche. Comme avec le flux de travail de suppression, 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 quelle action effectuer en fonction de l’élément SelectedValueBrochureOptions RadioButtonList :

  • Si la SelectedValue valeur est 1, nous voulons continuer à utiliser le même BrochurePath paramètre. Par conséquent, nous devons définir le paramètre brochurePath de l'ObjectDataSource sur la valeur existante BrochurePath de l’enregistrement en cours de mise à jour. Le paramètre brochurePath de l'ObjectDataSource peut être défini en utilisant e.NewValues["brochurePath"] = value.
  • Si SelectedValue est 2, nous voulons définir la valeur de l'enregistrement BrochurePath à NULL. Pour ce faire, définissez le paramètre ObjectDataSource sur brochurePath , ce qui entraîne l’utilisation d’une base de données Nothing dans l’instructionNULL.UPDATE S’il existe un fichier de brochure existant en cours de suppression, nous devons supprimer le fichier existant. Toutefois, nous voulons uniquement effectuer cette opération si la mise à jour se termine sans déclencher d’exception.
  • Si la SelectedValue valeur est 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 colonne de l’enregistrement BrochurePath . De plus, s’il existe un fichier de brochure existant en cours de remplacement, nous devons supprimer le fichier précédent. Toutefois, nous voulons uniquement effectuer cette opération si la mise à jour se termine sans déclencher d’exception.

Les étapes à suivre lorsque radioButtonList s SelectedValue est 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 appartient de refactoriser cette fonctionnalité en méthodes distinctes. Plus précisément, j’ai déplacé les fonctionnalités courantes en deux méthodes :

  • ProcessBrochureUpload(FileUpload, out bool) accepte comme entrée une instance de contrôle FileUpload et une valeur booléenne de sortie qui spécifie si l’opération de suppression ou de modification doit continuer 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 de la page deletedCategorysPdfPath si deletedCategorysPdfPath n’est pas null.

Le code de ces deux méthodes suit. Notez la similarité entre ProcessBrochureUpload et le gestionnaire d’événements ItemInserting de DetailsView du didacticiel précédent. Dans ce tutoriel, j’ai mis à jour les gestionnaires d’événements 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 Function ProcessBrochureUpload _
    (BrochureUpload As FileUpload, CancelOperation As Boolean) As String
    
    CancelOperation = False    ' by default, do not cancel operation
    If BrochureUpload.HasFile Then
        ' Make sure that a PDF has been uploaded
        If String.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName), _
            ".pdf", True) <> 0 Then
            
            UploadWarning.Text = _
                "Only PDF documents may be used for a category's brochure."
            UploadWarning.Visible = True
            CancelOperation = True
            Return Nothing
        End If
        Const BrochureDirectory As String = "~/Brochures/"
        Dim brochurePath As String = BrochureDirectory + BrochureUpload.FileName
        Dim fileNameWithoutExtension As String = _
            System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName)
        Dim iteration As Integer = 1
        While System.IO.File.Exists(Server.MapPath(brochurePath))
            brochurePath = String.Concat(BrochureDirectory, _
                fileNameWithoutExtension, "-", iteration, ".pdf")
            iteration += 1
        End While
        ' 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 Nothing
    End If
End Function
Private Sub DeleteRememberedBrochurePath()
    ' Is there a file to delete?
    If deletedCategorysPdfPath IsNot Nothing Then
        System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath))
    End If
End Sub

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

Protected Sub Categories_RowUpdating _
    (sender As Object, e As GridViewUpdateEventArgs) _
    Handles Categories.RowUpdating
    
    ' Reference the RadioButtonList
    Dim BrochureOptions As RadioButtonList = _
        CType(Categories.Rows(e.RowIndex).FindControl("BrochureOptions"), _
            RadioButtonList)
    ' Get BrochurePath information about the record being updated
    Dim categoryID As Integer = Convert.ToInt32(e.Keys("CategoryID"))
    Dim categoryAPI As New CategoriesBLL()
    Dim categoriesData As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = categoriesData(0)
    If BrochureOptions.SelectedValue = "1" Then
        ' Use current value for BrochurePath
        If category.IsBrochurePathNull() Then
            e.NewValues("brochurePath") = Nothing
        Else
            e.NewValues("brochurePath") = category.BrochurePath
        End If
    ElseIf BrochureOptions.SelectedValue = "2" Then
        ' Remove the current brochure (set it to NULL in the database)
        e.NewValues("brochurePath") = Nothing
    ElseIf BrochureOptions.SelectedValue = "3" Then
        ' Reference the BrochurePath FileUpload control
        Dim BrochureUpload As FileUpload = _
            CType(categories.Rows(e.RowIndex).FindControl("BrochureUpload"), _
                FileUpload)
        ' Process the BrochureUpload
        Dim cancelOperation As Boolean = False
        e.NewValues("brochurePath") = _
            ProcessBrochureUpload(BrochureUpload, cancelOperation)
        e.Cancel = cancelOperation
    Else
        ' Unknown value!
        Throw New ApplicationException( _
            String.Format("Invalid BrochureOptions value, {0}", _
                BrochureOptions.SelectedValue))
    End If
    If BrochureOptions.SelectedValue = "2" OrElse _
        BrochureOptions.SelectedValue = "3" Then
        
        ' "Remember" that we need to delete the old PDF file
        If (category.IsBrochurePathNull()) Then
            deletedCategorysPdfPath = Nothing
        Else
            deletedCategorysPdfPath = category.BrochurePath
        End If
    End If
End Sub
Protected Sub Categories_RowUpdated _
    (sender As Object, e As GridViewUpdatedEventArgs) _
    Handles Categories.RowUpdated
    
    ' If there were no problems and we updated the PDF file, 
    ' then delete the existing one
    If e.Exception Is Nothing Then
        DeleteRememberedBrochurePath()
    End If
End Sub

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 BrochureOptions valeur de propriété de SelectedValue RadioButtonList.

Avec ce code en place, vous pouvez modifier une catégorie et l’utiliser avec sa brochure actuelle, n’utiliser aucune brochure ou en charger une nouvelle. Allez-y et essayez-le. Définissez des points d’arrêt dans les RowUpdating gestionnaires d’événements et RowUpdated les gestionnaires d’événements pour avoir un sens 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, pour nom du paramètre, la valeur de la propriété ImageField DataImageUrlField, et pour valeur du paramètre, la valeur entrée dans la zone de texte de l'interface d'édition. Ce comportement convient lorsque l’image est enregistrée en tant que fichier sur le système de fichiers et contient DataImageUrlField l’URL complète de l’image. Dans ce cas, 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 n’autorise pas l’utilisateur à téléverser une nouvelle image, mais elle lui permet de modifier l’URL de l’image de la valeur actuelle à une autre. Pour ce tutoriel, cependant, l'interface d'édition par défaut de ImageField est insuffisante, car les données binaires Picture sont stockées directement dans la base de données et la propriété ne contient que le DataImageUrlFieldCategoryID.

Pour mieux comprendre ce qui se passe dans notre tutoriel lorsqu’un utilisateur modifie une ligne avec un Champ ImageField, considérez l’exemple suivant : un utilisateur modifie une ligne avec CategoryID 10, ce qui entraîne le Picture rendu de ImageField en tant que zone de texte avec la valeur 10. Imaginez que l’utilisateur modifie la valeur de cette zone de texte sur 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 envoie ce paramètre (et les CategoryNameDescription paramètres), 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 DataKey la grille sont identiques.

Bien que 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. Au lieu de cela, nous souhaitons offrir un contrôle FileUpload que l’utilisateur final peut utiliser pour modifier l’image de catégorie. Contrairement à la BrochurePath valeur, pour ces didacticiels, 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’il n’y a aucune image associée que l’utilisateur peut charger une nouvelle image ou quitter l’image actuelle as-is.

Pour personnaliser l’interface d’édition d’ImageField, nous devons la convertir en modèleField. Dans le tag intelligent de GridView, cliquez sur le lien Modifier les colonnes, sélectionnez ImageField, puis cliquez sur le lien Convertir ce champ en TemplateField.

Convertir ImageField en ChampTemplate

Figure 16 : Convertir ImageField en TemplateField

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

<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 le EditItemTemplate pour utiliser un contrôle de téléchargement de fichiers. Dans l'étiquette intelligente de GridView, cliquez sur le lien Modifier les modèles, puis sélectionnez TemplateField PictureEditItemTemplate dans la liste déroulante. Dans le modèle, vous devriez voir une zone de texte ; supprimez-la. Ensuite, faites glisser un contrôle FileUpload de la boîte à outils dans le modèle, en définissant sa propriété ID à PictureUpload. Ajoutez également le texte Pour modifier l’image de la catégorie, spécifiez une nouvelle image. Pour conserver la même image de catégorie, laissez également le champ vide dans le modèle.

Ajouter un contrôle FileUpload à EditItemTemplate

Figure 17 : Ajouter un contrôle FileUpload à l’objet EditItemTemplate (Cliquez pour afficher l’image de taille complète)

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 comme avant, mais en cliquant sur le bouton Modifier, la colonne image est affichée sous forme de 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 (Cliquez pour afficher l’image de taille complète)

Rappelez-vous que l'ObjectDataSource est configuré pour appeler la méthode de la classe CategoriesBLLUpdateCategory qui prend en entrée les données binaires de la photo sous forme de tableau Byte. Si ce tableau est Nothing, toutefois, la surcharge alternative UpdateCategory 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 RowUpdating GridView, nous devons référencer par programmation le PictureUpload contrôle FileUpload et déterminer si un fichier a été chargé. Si l’un 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 ici existe déjà dans le gestionnaire d’événements DetailsView ItemInserting . Par conséquent, j’ai refactorisé les fonctionnalités courantes dans une nouvelle méthode, ValidPictureUploadet j’ai 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 RowUpdating GridView. Il est important que ce code arrive avant 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
Dim PictureUpload As FileUpload = _
    CType(categories.Rows(e.RowIndex).FindControl("PictureUpload"), _
        FileUpload)
If PictureUpload.HasFile Then
    ' Make sure the picture upload is valid
    If ValidPictureUpload(PictureUpload) Then
        e.NewValues("picture") = PictureUpload.FileBytes
    Else
        ' Invalid file upload, cancel update and exit event handler
        e.Cancel = True
        Exit Sub
    End If
End If

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 JPG ; il est appelé uniquement si un fichier image est chargé. Si aucun fichier n’est chargé, le paramètre image n’est pas défini et utilise donc sa valeur Nothingpar défaut . Si une image est chargée et que ValidPictureUpload retourne True, le paramètre picture reçoit les données binaires de l’image chargée ; si la méthode retourne False, le processus de mise à jour est annulé et le gestionnaire d’événements est quitté.

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

Private Function ValidPictureUpload(ByVal PictureUpload As FileUpload) As Boolean
    ' Make sure that a JPG has been uploaded
    If String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
        ".jpg", True) <> 0 AndAlso _
        String.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), _
        ".jpeg", True) <> 0 Then
        
        UploadWarning.Text = _
            "Only JPG documents may be used for a category's picture."
        UploadWarning.Visible = True
        Return False
    Else
        Return True
    End If
End Function

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

Rappelez-vous que les huit images 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 effectuant les étapes suivantes :

  1. Enregistrez les images bitmap sur votre disque dur. Visitez la UpdatingAndDeleting.aspx page de 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 sous forme d’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 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 Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim categoryID As Integer = _
        Convert.ToInt32(Request.QueryString("CategoryID"))
    ' Get information about the specified category
    Dim categoryAPI As New CategoriesBLL()
    Dim categories As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = 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)
End Sub

Remarque

Les interfaces d'insertion et de modification de la page pourraient bénéficier d'un peu plus de travail. Les BoundFields dans DetailsView et GridView doivent être convertis en TemplateFields. Comme CategoryName n’autorise pas les valeurs NULL, un RequiredFieldValidator doit être ajouté. Et la Description zone de texte doit probablement être convertie en zone de texte à plusieurs lignes. Je laisse ces touches finales comme un exercice pour vous.

Résumé

Ce tutoriel complète notre présentation de l’utilisation des 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 interface telle que le glisser-déplacer. Toutefois, comme indiqué dans le didacticiel Chargement de fichiers , le contrôle FileUpload est adapté uniquement aux chargements de fichiers relativement petits, idéalement sans dépasser 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 plus rapide.

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 en tant que consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 2.0 en 24 heures. On peut le joindre à mitchell@4GuysFromRolla.com.

Merci spécial à

Cette série de tutoriels a été examinée par de nombreux réviseurs utiles. Le réviseur principal 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.