Mise à jour et suppression de données binaires existantes (C#)
par Scott Mitchell
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é Insert
automatiquement les méthodes , Update
et 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.
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 CategoryName
valeurs , 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))
Le dernier écran de l’Assistant nous demande de nommer la nouvelle méthode TableAdapter. Entrez UpdateWithPicture
et cliquez sur Terminer.
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 CategoryName
valeurs , Description
et 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.aspx
UpdatingAndDeleting.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
.
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.
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
.
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.
Figure 6 : Ajouter une catégorie de test avec une brochure et une image (cliquer pour afficher une image en taille réelle)
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.
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.
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 à true
la 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).
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 DataImageUrlField
CategoryID
.
Figure 11 : GridView n’a pas d’interface d’édition pour BrochurePath
(Cliquez pour afficher l’image en taille réelle)
Personnalisation de l’interfaceBrochurePath
d’é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é true
sur Selected
.
Figure 12 : Ajouter trois ListItem
à RadioButtonList
Sous RadioButtonList, ajoutez un contrôle FileUpload nommé BrochureUpload
. Définissez sa Visible
propriété sur false
.
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.
Figure 14 : Initialement, l’option Utiliser la brochure actuelle est sélectionnée (Cliquer pour afficher l’image en taille réelle)
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 laBrochurePath
colonne
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êmeBrochurePath
paramètre. Par conséquent, nous devons définir le paramètre ObjectDataSourcebrochurePath
sur la valeur existanteBrochurePath
de l’enregistrement en cours de mise à jour. Le paramètre ObjectDataSourcebrochurePath
peut être défini à l’aide dee.NewValues["brochurePath"] = value
. - Si a la
SelectedValue
valeur 2, nous voulons définir la valeur de l’enregistrementBrochurePath
surNULL
. Pour ce faire, définissez le paramètre ObjectDataSourcebrochurePath
sur , ce qui entraîne l’utilisation d’une base de donnéesNULL
dans l’instructionUPDATE
.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’enregistrementBrochurePath
. 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é ounull
si aucun fichier n’a été enregistré.DeleteRememberedBrochurePath
supprime le fichier spécifié par le chemin d’accès dans la variabledeletedCategorysPdfPath
de page sideletedCategorysPdfPath
n’est pasnull
.
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.
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.
Figure 17 : Ajouter un contrôle FileUpload à (EditItemTemplate
Cliquer 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.
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 true
est 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 :
- 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. - Ouvrez l’image dans l’éditeur d’images de votre choix. Vous pouvez utiliser Microsoft Paint, par exemple.
- Enregistrez la bitmap en tant qu’image JPG.
- 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.