Aggiornamento ed eliminazione di dati binari esistenti (VB)
Nelle esercitazioni precedenti è stato illustrato come il controllo GridView semplifica la modifica e l'eliminazione dei dati di testo. In questa esercitazione viene illustrato come il controllo GridView consente anche di modificare ed eliminare dati binari, indipendentemente dal fatto che tali dati binari vengano salvati nel database o archiviati nel file system.
Introduzione
Nelle ultime tre esercitazioni sono state aggiunte alcune funzionalità per l'uso dei dati binari. È stata avviata l'aggiunta di una BrochurePath
colonna alla Categories
tabella e l'architettura è stata aggiornata di conseguenza. Sono stati aggiunti anche i metodi livello di accesso ai dati e al livello della logica di business per lavorare con la colonna esistente Picture
della tabella Categories, che contiene il contenuto binario di un file di immagine. Abbiamo creato pagine Web per presentare i dati binari in un gridView un collegamento di download per la brochure, con l'immagine della categoria mostrata in un <img>
elemento e abbiamo aggiunto un controllo DetailsView per consentire agli utenti di aggiungere una nuova categoria e caricare i dati della brochure e dell'immagine.
Tutto ciò che rimane da implementare è la possibilità di modificare ed eliminare le categorie esistenti, che verranno eseguite in questa esercitazione usando la modifica e l'eliminazione delle funzionalità predefinite di GridView. Quando si modifica una categoria, l'utente potrà caricare facoltativamente una nuova immagine o fare in modo che la categoria continui a usare quella esistente. Per la brochure, possono scegliere di utilizzare la brochure esistente, di caricare una nuova brochure o di indicare che la categoria non ha più una brochure associata. Iniziamo!
Passaggio 1: Aggiornamento del livello di accesso ai dati
IL DAL include i Insert
metodi , Update
e Delete
generati automaticamente, ma questi metodi sono stati generati in base alla CategoriesTableAdapter
query principale, che non include la Picture
colonna . Pertanto, i Insert
metodi e Update
non includono parametri per specificare i dati binari per l'immagine della categoria. Come illustrato nell'esercitazione precedente, è necessario creare un nuovo metodo TableAdapter per aggiornare la Categories
tabella quando si specificano dati binari.
Aprire il set di dati tipizzato e, dal Designer, fare clic con il pulsante destro del mouse sull'intestazione CategoriesTableAdapter
s e scegliere Aggiungi query dal menu di scelta rapida per avviare la Configurazione guidata query TableAdapter. Questa procedura guidata inizia chiedendo in che modo la query TableAdapter deve accedere al database. Scegliere Usa istruzioni SQL e fare clic su Avanti. Il passaggio successivo richiede il tipo di query da generare. Poiché si sta creando una query per aggiungere un nuovo record alla Categories
tabella, scegliere UPDATE e fare clic su Avanti.
Figura 1: Selezionare l'opzione UPDATE (fare clic per visualizzare l'immagine a dimensione intera)
È ora necessario specificare l'istruzione UPDATE
SQL. La procedura guidata suggerisce automaticamente un'istruzione UPDATE
corrispondente alla query principale di TableAdapter (una che aggiorna i CategoryName
valori , Description
e BrochurePath
). Modificare l'istruzione in modo che la Picture
colonna sia inclusa insieme a un @Picture
parametro, come illustrato di seguito:
UPDATE [Categories] SET
[CategoryName] = @CategoryName,
[Description] = @Description,
[BrochurePath] = @BrochurePath ,
[Picture] = @Picture
WHERE (([CategoryID] = @Original_CategoryID))
La schermata finale della procedura guidata chiede di assegnare un nome al nuovo metodo TableAdapter. Immettere UpdateWithPicture
e fare clic su Fine.
Figura 2: Assegnare un nome al nuovo metodo UpdateWithPicture
TableAdapter (fare clic per visualizzare l'immagine a dimensione intera)
Passaggio 2: Aggiunta dei metodi del livello della logica di business
Oltre ad aggiornare DAL, è necessario aggiornare il BLL per includere i metodi per l'aggiornamento e l'eliminazione di una categoria. Questi sono i metodi che verranno richiamati dal livello presentazione.
Per eliminare una categoria, è possibile usare il CategoriesTableAdapter
metodo generato Delete
automaticamente. Aggiungere il metodo seguente alla 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
Per questa esercitazione, è possibile creare due metodi per aggiornare una categoria, una che prevede i dati immagine binari e richiama il UpdateWithPicture
metodo appena aggiunto a CategoriesTableAdapter
e un altro che accetta solo i CategoryName
valori , Description
e BrochurePath
e usa CategoriesTableAdapter
l'istruzione generata Update
automaticamente della classe . La logica dietro l'uso di due metodi è che in alcune circostanze, un utente potrebbe voler aggiornare l'immagine della categoria insieme agli altri campi, nel qual caso l'utente dovrà caricare la nuova immagine. I dati binari dell'immagine caricata possono quindi essere usati nell'istruzione UPDATE
. In altri casi, l'utente potrebbe essere interessato solo all'aggiornamento, ad esempio il nome e la descrizione. Tuttavia, se l'istruzione UPDATE
prevede anche i dati binari per la Picture
colonna, è necessario fornire tali informazioni. Ciò richiederebbe un'ulteriore corsa al database per riportare i dati immagine per il record da modificare. Pertanto, vogliamo due UPDATE
metodi. Il livello della logica di business determinerà quale usare in base al fatto che i dati dell'immagine vengano forniti durante l'aggiornamento della categoria.
Per facilitare questa operazione, aggiungere due metodi alla CategoriesBLL
classe , entrambi denominati UpdateCategory
. Il primo deve accettare tre String
s, una Byte
matrice e un Integer
come parametri di input; il secondo, solo tre String
s e un oggetto Integer
. I String
parametri di input sono relativi al nome, alla descrizione e al percorso del file della brochure della categoria, la Byte
matrice è relativa al contenuto binario dell'immagine della categoria e Integer
identifica l'oggetto CategoryID
del record da aggiornare. Si noti che il primo overload richiama il secondo se la matrice passata Byte
è 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
Passaggio 3: Copia della funzionalità Di inserimento e visualizzazione
Nell'esercitazione precedente è stata creata una pagina denominata UploadInDetailsView.aspx
che elenca tutte le categorie in un controllo GridView e ha fornito un controllo DetailsView per aggiungere nuove categorie al sistema. In questa esercitazione verrà esteso GridView per includere la modifica e l'eliminazione del supporto. Invece di continuare a lavorare da UploadInDetailsView.aspx
, inserire invece le modifiche di questa esercitazione nella UpdatingAndDeleting.aspx
pagina dalla stessa cartella, ~/BinaryData
. Copiare e incollare il markup dichiarativo e il codice da UploadInDetailsView.aspx
a UpdatingAndDeleting.aspx
.
Per iniziare, aprire la UploadInDetailsView.aspx
pagina. Copiare tutta la sintassi dichiarativa all'interno dell'elemento <asp:Content>
, come illustrato nella figura 3. UpdatingAndDeleting.aspx
Aprire e incollare il markup all'interno del relativo <asp:Content>
elemento. Analogamente, copiare il codice dalla classe code-behind della UploadInDetailsView.aspx
pagina a UpdatingAndDeleting.aspx
.
Figura 3: Copiare il markup dichiarativo da UploadInDetailsView.aspx
(fare clic per visualizzare l'immagine a dimensione intera)
Dopo aver copiato il markup dichiarativo e il codice, visitare UpdatingAndDeleting.aspx
. Dovrebbe essere visualizzato lo stesso output e avere la stessa esperienza utente di con UploadInDetailsView.aspx
la pagina dell'esercitazione precedente.
Passaggio 4: Aggiunta del supporto per l'eliminazione a ObjectDataSource e GridView
Come illustrato di nuovo nell'esercitazione Panoramica dell'inserimento, dell'aggiornamento e dell'eliminazione dei dati , GridView offre funzionalità di eliminazione predefinite e queste funzionalità possono essere abilitate al segno di spunta di una casella di controllo se l'origine dati sottostante della griglia supporta l'eliminazione. Attualmente ObjectDataSource a cui gridView è associato (CategoriesDataSource
) non supporta l'eliminazione.
Per risolvere questo problema, fare clic sull'opzione Configura origine dati dallo smart tag ObjectDataSource s per avviare la procedura guidata. La prima schermata mostra che ObjectDataSource è configurato per funzionare con la CategoriesBLL
classe . Fare clic su Avanti. Attualmente vengono specificate solo le proprietà ObjectDataSource s InsertMethod
e SelectMethod
. Tuttavia, la procedura guidata popola automaticamente gli elenchi a discesa nelle schede UPDATE e DELETE rispettivamente con i UpdateCategory
metodi e DeleteCategory
. Ciò è dovuto al CategoriesBLL
fatto che nella classe sono stati contrassegnati questi metodi usando DataObjectMethodAttribute
come metodi predefiniti per l'aggiornamento e l'eliminazione.
Per il momento, impostare l'elenco a discesa della scheda UPDATE su (Nessuno), ma lasciare l'elenco a discesa ELIMINA scheda s impostato su DeleteCategory
. Si tornerà a questa procedura guidata nel passaggio 6 per aggiungere il supporto per l'aggiornamento.
Figura 4: Configurare ObjectDataSource per l'uso del metodo (fare clic per visualizzare l'immagineDeleteCategory
a dimensione intera)
Nota
Al termine della procedura guidata, Visual Studio potrebbe chiedere se si desidera aggiornare campi e chiavi, che rigenerano i campi dei controlli Web dati. Scegliere No, perché la scelta di Sì sovrascriverà le personalizzazioni dei campi che potrebbero essere state apportate.
ObjectDataSource includerà ora un valore per la relativa DeleteMethod
proprietà e un oggetto DeleteParameter
. Tenere presente che quando si usa la procedura guidata per specificare i metodi, Visual Studio imposta la proprietà original_{0}
ObjectDataSource su OldValuesParameterFormatString
, che causa problemi con le chiamate al metodo di aggiornamento ed eliminazione. Di conseguenza, cancellare completamente questa proprietà o reimpostarla sul valore predefinito, {0}
. Se è necessario aggiornare la memoria in questa proprietà ObjectDataSource, vedere l'esercitazione Panoramica dell'inserimento, dell'aggiornamento e dell'eliminazione dei dati .
Dopo aver completato la procedura guidata e corretto OldValuesParameterFormatString
, il markup dichiarativo di ObjectDataSource dovrebbe essere simile al seguente:
<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>
Dopo aver configurato ObjectDataSource, aggiungere le funzionalità di eliminazione a GridView selezionando la casella di controllo Abilita eliminazione dallo smart tag di GridView. Verrà aggiunto un campo CommandField a GridView la cui ShowDeleteButton
proprietà è impostata su True
.
Figura 5: Abilitare il supporto per l'eliminazione in GridView (fare clic per visualizzare l'immagine a dimensione intera)
Testare la funzionalità di eliminazione. Esiste una chiave esterna tra la Products
tabella s CategoryID
e la Categories
tabella s CategoryID
, pertanto si otterrà un'eccezione di violazione del vincolo di chiave esterna se si tenta di eliminare una delle prime otto categorie. Per testare questa funzionalità, aggiungere una nuova categoria, fornendo sia una brochure che un'immagine. La categoria di test, illustrata nella figura 6, include un file di brochure di test denominato Test.pdf
e un'immagine di test. La figura 7 mostra GridView dopo l'aggiunta della categoria di test.
Figura 6: Aggiungere una categoria di test con una brochure e un'immagine (fare clic per visualizzare l'immagine a dimensione intera)
Figura 7: Dopo aver inserito la categoria di test, viene visualizzata in GridView (fare clic per visualizzare l'immagine a dimensione intera)
In Visual Studio aggiornare la Esplora soluzioni. Verrà ora visualizzato un nuovo file nella ~/Brochures
cartella ( Test.pdf
vedere la figura 8).
Fare quindi clic sul collegamento Elimina nella riga Categoria di test, causando il postback della pagina e il CategoriesBLL
metodo della DeleteCategory
classe. In questo modo verrà richiamato il metodo dal Delete
servizio dati, causando l'invio dell'istruzione appropriata DELETE
al database. I dati vengono quindi reindirizzato a GridView e il markup viene inviato al client con la categoria di test non più presente.
Mentre il flusso di lavoro di eliminazione ha rimosso correttamente il record categoria di test dalla Categories
tabella, non ha rimosso il file brochure dal file system del server Web. Aggiornare il Esplora soluzioni e si noterà che Test.pdf
è ancora seduto nella ~/Brochures
cartella.
Figura 8: Il Test.pdf
file non è stato eliminato dal file system del server Web
Passaggio 5: Rimozione del file della brochure della categoria eliminata
Uno dei lati negativi dell'archiviazione di dati binari esterni al database è che è necessario eseguire passaggi aggiuntivi per pulire questi file quando il record di database associato viene eliminato. GridView e ObjectDataSource forniscono eventi che vengono generati sia prima che dopo l'esecuzione del comando di eliminazione. È effettivamente necessario creare gestori eventi per gli eventi pre-e post-azione. Prima che il Categories
record venga eliminato, è necessario determinare il percorso del file PDF, ma non si vuole eliminare il PDF prima che la categoria venga eliminata in caso di eccezione e la categoria non venga eliminata.
L'evento GridView viene generato prima che sia stato richiamato il comando di eliminazione di RowDeleting
ObjectDataSource, mentre il relativo RowDeleted
evento viene generato dopo. Creare gestori eventi per questi due eventi usando il codice seguente:
' 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
RowDeleting
Nel gestore eventi, l'oggetto CategoryID
della riga eliminata viene afferrato dall'insieme GridView, DataKeys
a cui è possibile accedere in questo gestore eventi tramite la e.Keys
raccolta. Successivamente, viene richiamata la CategoriesBLL
classe s GetCategoryByCategoryID(categoryID)
per restituire informazioni sul record eliminato. Se l'oggetto restituito ha un valore diversoNULL``BrochurePath
, viene archiviato CategoriesDataRow
nella variabile deletedCategorysPdfPath
di pagina in modo che il file possa essere eliminato nel RowDeleted
gestore eventi.
Nota
Anziché recuperare i BrochurePath
dettagli per il Categories
record eliminato nel RowDeleting
gestore eventi, è possibile aggiungere in alternativa l'oggetto BrochurePath
alla proprietà GridView e DataKeyNames
accedere al valore del record tramite la e.Keys
raccolta. In questo modo, aumentare leggermente le dimensioni dello stato di visualizzazione di GridView, ma ridurrebbe la quantità di codice necessaria e salvare un viaggio nel database.
Dopo aver richiamato il comando Di eliminazione sottostante di ObjectDataSource, viene generato il gestore eventi gridView s RowDeleted
. Se non sono presenti eccezioni nell'eliminazione dei dati e esiste un valore per deletedCategorysPdfPath
, il PDF viene eliminato dal file system. Si noti che questo codice aggiuntivo non è necessario per pulire i dati binari della categoria associati alla relativa immagine. Questo perché i dati dell'immagine vengono archiviati direttamente nel database, quindi l'eliminazione della Categories
riga elimina anche i dati dell'immagine della categoria.
Dopo aver aggiunto i due gestori eventi, eseguire di nuovo questo test case. Quando si elimina la categoria, viene eliminato anche il pdf associato.
L'aggiornamento di dati binari associati a un record esistente offre alcuni problemi interessanti. La parte restante di questa esercitazione consente di aggiungere funzionalità di aggiornamento alla brochure e all'immagine. Il passaggio 6 illustra le tecniche per aggiornare le informazioni sulla brochure mentre il passaggio 7 esamina l'aggiornamento dell'immagine.
Passaggio 6: Aggiornamento della brochure di una categoria
Come illustrato nell'esercitazione Panoramica dell'inserimento, dell'aggiornamento e dell'eliminazione dei dati, GridView offre il supporto di modifica a livello di riga predefinito che può essere implementato dal segno di spunta di una casella di controllo se l'origine dati sottostante è configurata in modo appropriato. Attualmente, ObjectDataSource non è ancora configurato per includere il supporto per l'aggiornamento CategoriesDataSource
, quindi consente di aggiungere tale elemento.
Fare clic sul collegamento Configura origine dati dalla procedura guidata di ObjectDataSource e procedere al secondo passaggio. A causa dell'uso in , l'elenco a discesa UPDATE deve essere popolato automaticamente con l'overload DataObjectMethodAttribute
UpdateCategory
che accetta quattro parametri di input (per tutte le colonne ma Picture
).CategoriesBLL
Modificare questa operazione in modo che usi l'overload con cinque parametri.
Figura 9: Configurare ObjectDataSource per usare il UpdateCategory
metodo che include un parametro per Picture
(fare clic per visualizzare l'immagine a dimensioni complete)
ObjectDataSource includerà ora un valore per la relativa UpdateMethod
proprietà e la relativa UpdateParameter
proprietà. Come indicato nel passaggio 4, Visual Studio imposta la proprietà original_{0}
ObjectDataSource su OldValuesParameterFormatString
quando si usa la procedura guidata Configura origine dati. In questo modo si verificheranno problemi con le chiamate al metodo update ed delete. Pertanto, deselezionare completamente questa proprietà o reimpostarla nel valore predefinito, {0}
.
Dopo aver completato la procedura guidata e corretto OldValuesParameterFormatString
, il markup dichiarativo di ObjectDataSource deve essere simile al seguente:
<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>
Per attivare le funzionalità di modifica predefinite di GridView, selezionare l'opzione Abilita modifica dallo smart tag di GridView. Verrà impostata la proprietà True
CommandField su ShowEditButton
, che comporta l'aggiunta di un pulsante Modifica (e i pulsanti Aggiorna e Annulla per la riga da modificare).
Figura 10: Configurare GridView per supportare la modifica (fare clic per visualizzare l'immagine a dimensioni complete)
Visitare la pagina tramite un browser e fare clic su uno dei pulsanti Modifica riga. I CategoryName
valori e Description
BoundField vengono visualizzati come caselle di testo. BrochurePath
TemplateField non ha un EditItemTemplate
oggetto , quindi continua a mostrare il ItemTemplate
relativo collegamento alla brochure. ImageField Picture
esegue il rendering come TextBox la cui Text
proprietà viene assegnata al valore del valore imageField DataImageUrlField
, in questo caso CategoryID
.
Figura 11: GridView manca di un'interfaccia di modifica per BrochurePath
(fare clic per visualizzare l'immagine a dimensioni complete)
Personalizzazione dell'interfacciaBrochurePath
di modifica
È necessario creare un'interfaccia BrochurePath
di modifica per TemplateField, una che consente all'utente di:
- Lasciare la brochure della categoria come è,
- Aggiornare la brochure della categoria caricando una nuova brochure o
- Rimuovere completamente la brochure della categoria (nel caso in cui la categoria non abbia più una brochure associata).
È anche necessario aggiornare l'interfaccia Picture
di modifica di ImageField, ma questo verrà visualizzato nel passaggio 7.
Nella smart tag di GridView fare clic sul collegamento Modifica modelli e selezionare BrochurePath
TemplateField nell'elenco EditItemTemplate
a discesa. Aggiungere un controllo Web RadioButtonList a questo modello, impostandone la ID
proprietà su BrochureOptions
e sulla relativa AutoPostBack
proprietà su True
. Nella Finestra Proprietà fare clic sui puntini di sospensione nella Items
proprietà, che verrà visualizzata la ListItem
Editor raccolta. Aggiungere rispettivamente le tre opzioni seguenti con Value
s 1, 2 e 3:
- Usare la brochure corrente
- Rimuovere la brochure corrente
- Caricare una nuova brochure
Impostare la prima ListItem
proprietà True
su Selected
.
Figura 12: Aggiungere tre ListItem
s all'elenco RadioButtonList
Sotto radioButtonList aggiungere un controllo FileUpload denominato BrochureUpload
. Impostare la proprietà Visible
su False
.
Figura 13: Aggiungere un controllo RadioButtonList e FileUpload all'oggetto EditItemTemplate
(fare clic per visualizzare l'immagine a dimensioni complete)
Questo oggetto RadioButtonList offre le tre opzioni per l'utente. L'idea è che il controllo FileUpload verrà visualizzato solo se è selezionata l'ultima opzione Carica nuova brochure. A questo scopo, creare un gestore eventi per l'evento RadioButtonList SelectedIndexChanged
e aggiungere il codice seguente:
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
Poiché i controlli RadioButtonList e FileUpload si trovano all'interno di un modello, è necessario scrivere un bit di codice per accedere a questi controlli a livello di codice. Il SelectedIndexChanged
gestore eventi viene passato un riferimento di RadioButtonList nel sender
parametro di input. Per ottenere il controllo FileUpload, è necessario ottenere il controllo padre radioButtonList e usare il FindControl("controlID")
metodo da lì. Dopo avere un riferimento ai controlli RadioButtonList e FileUpload, la proprietà del Visible
controllo FileUpload è impostata su solo se l'oggetto RadioButtonList è SelectedValue
uguale a True
3, ovvero per Value
il caricamento di una nuova brochure ListItem
.
Con questo codice sul posto, è necessario testare l'interfaccia di modifica. Fare clic sul pulsante Modifica per una riga. Inizialmente, è consigliabile selezionare l'opzione Usa brochure corrente. La modifica dell'indice selezionato causa un postback. Se viene selezionata la terza opzione, viene visualizzato il controllo FileUpload, altrimenti è nascosto. La figura 14 mostra l'interfaccia di modifica quando viene prima fatto clic sul pulsante Modifica; La figura 15 mostra l'interfaccia dopo l'opzione Carica nuova brochure.
Figura 14: Inizialmente, l'opzione Use current brochure è selezionata (Fare clic per visualizzare l'immagine a dimensioni complete)
Figura 15: scelta dell'opzione Carica nuova brochure Visualizza il controllo FileUpload (Fare clic per visualizzare l'immagine full-size)
Salvataggio del file della brochure e aggiornamento dellaBrochurePath
colonna
Quando viene fatto clic sul pulsante Aggiornamento di GridView, viene generato il relativo RowUpdating
evento. Il comando di aggiornamento di ObjectDataSource viene richiamato e quindi viene generato l'evento GridView s RowUpdated
. Come per l'eliminazione del flusso di lavoro, è necessario creare gestori eventi per entrambi questi eventi. RowUpdating
Nel gestore eventi è necessario determinare l'azione da eseguire in base all'oggetto SelectedValue
BrochureOptions
RadioButtonList:
- Se è
SelectedValue
1, si vuole continuare a usare la stessaBrochurePath
impostazione. È quindi necessario impostare il parametro ObjectDataSource sulbrochurePath
valore esistenteBrochurePath
del record aggiornato. Il parametro ObjectDataSource sbrochurePath
può essere impostato usandoe.NewValues["brochurePath"] = value
. - Se è
SelectedValue
2, si vuole impostare il valore delBrochurePath
record suNULL
. Questa operazione può essere eseguita impostando il parametro ObjectDataSource subrochurePath
, che comporta l'uso di un databaseNULL
nell'istruzioneUPDATE
.Nothing
Se è presente un file brochure esistente da rimuovere, è necessario eliminare il file esistente. Tuttavia, si vuole eseguire questa operazione solo se l'aggiornamento viene completato senza generare un'eccezione. - Se è
SelectedValue
3, si vuole assicurarsi che l'utente abbia caricato un file PDF e quindi salvarlo nel file system e aggiornare il valore della colonna delBrochurePath
record. Inoltre, se è presente un file brochure esistente che viene sostituito, è necessario eliminare il file precedente. Tuttavia, si vuole eseguire questa operazione solo se l'aggiornamento viene completato senza generare un'eccezione.
I passaggi necessari per essere completati quando RadioButtonList s SelectedValue
è 3 sono praticamente identici a quelli usati dal gestore eventi detailsView.ItemInserting
Questo gestore eventi viene eseguito quando viene aggiunto un nuovo record di categoria dal controllo DetailsView aggiunto nell'esercitazione precedente. Di conseguenza, viene eseguito il refactoring di questa funzionalità in metodi separati. In particolare, ho spostato le funzionalità comuni in due metodi:
ProcessBrochureUpload(FileUpload, out bool)
accetta come input un'istanza del controllo FileUpload e un valore booleano di output che specifica se l'operazione di eliminazione o modifica deve continuare o se deve essere annullata a causa di un errore di convalida. Questo metodo restituisce il percorso del file salvato onull
se non è stato salvato alcun file.DeleteRememberedBrochurePath
elimina il file specificato dal percorso nella variabiledeletedCategorysPdfPath
di pagina sedeletedCategorysPdfPath
nonnull
è .
Di seguito è riportato il codice per questi due metodi. Si noti la somiglianza tra ProcessBrochureUpload
e il gestore eventi detailsView dell'esercitazione ItemInserting
precedente. In questa esercitazione sono stati aggiornati i gestori eventi di DetailsView per usare questi nuovi metodi. Scaricare il codice associato a questa esercitazione per visualizzare le modifiche ai gestori eventi 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
I gestori eventi e di RowUpdating
GridView usano i ProcessBrochureUpload
metodi e DeleteRememberedBrochurePath
, come illustrato nel codice RowUpdated
seguente:
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
Si noti che il RowUpdating
gestore eventi usa una serie di istruzioni condizionali per eseguire l'azione appropriata in base al valore della BrochureOptions
proprietà RadioButtonList.SelectedValue
Con questo codice, è possibile modificare una categoria e usarla per la brochure corrente, non utilizzare brochure o caricarne una nuova. Vai avanti e provalo. Impostare i punti di interruzione nei RowUpdating
gestori eventi e RowUpdated
per ottenere un'idea del flusso di lavoro.
Passaggio 7: Caricamento di una nuova immagine
L'interfaccia Picture
di modifica ImageField esegue il rendering come casella di testo popolata con il valore della relativa DataImageUrlField
proprietà. Durante il flusso di lavoro di modifica, GridView passa un parametro a ObjectDataSource con il nome del parametro il valore della proprietà ImageField s DataImageUrlField
e il valore del parametro immesso nella casella di testo nell'interfaccia di modifica. Questo comportamento è adatto quando l'immagine viene salvata come file nel file system e DataImageUrlField
contiene l'URL completo dell'immagine. In tali circostanze, l'interfaccia di modifica visualizza l'URL dell'immagine nella casella di testo, che l'utente può modificare e aver salvato di nuovo nel database. Concessa, questa interfaccia predefinita non consente all'utente di caricare una nuova immagine, ma consente di modificare l'URL dell'immagine dal valore corrente a un altro. Per questa esercitazione, tuttavia, l'interfaccia di modifica predefinita di ImageField non è sufficiente perché i Picture
dati binari vengono archiviati direttamente nel database e la DataImageUrlField
proprietà contiene solo .CategoryID
Per comprendere meglio cosa accade nell'esercitazione quando un utente modifica una riga con un oggetto ImageField, si consideri l'esempio seguente: un utente modifica una riga con CategoryID
10, causando il rendering di Picture
ImageField come casella di testo con il valore 10. Si supponga che l'utente cambi il valore in questa casella di testo su 50 e faccia clic sul pulsante Aggiorna. Si verifica un postback e GridView crea inizialmente un parametro denominato CategoryID
con il valore 50. Tuttavia, prima che GridView invii questo parametro (e i CategoryName
parametri e Description
), aggiunge i valori della DataKeys
raccolta. Pertanto, sovrascrive il CategoryID
parametro con il valore sottostante CategoryID
della riga corrente, 10. In breve, l'interfaccia di modifica di ImageField non ha alcun effetto sul flusso di lavoro di modifica per questa esercitazione perché i nomi della proprietà ImageField e DataImageUrlField
il valore della DataKey
griglia sono uno nello stesso.
Anche se ImageField semplifica la visualizzazione di un'immagine basata sui dati del database, non si vuole fornire una casella di testo nell'interfaccia di modifica. Si vuole invece offrire un controllo FileUpload che l'utente finale può usare per modificare l'immagine della categoria. A differenza del BrochurePath
valore, per queste esercitazioni si è deciso di richiedere che ogni categoria debba avere un'immagine. Pertanto, non è necessario consentire all'utente di indicare che non vi è alcuna immagine associata che l'utente può caricare una nuova immagine o lasciare invariata l'immagine corrente.
Per personalizzare l'interfaccia di modifica di ImageField, è necessario convertirla in un oggetto TemplateField. Dallo smart tag gridView fare clic sul collegamento Modifica colonne, selezionare ImageField e fare clic sul collegamento Convert this field into a TemplateField (Converti questo campo in un campo modello).
Figura 16: Convertire imageField in un campo modello
La conversione di ImageField in un campo modello in questo modo genera un campo Modello con due modelli. Come illustrato nella sintassi dichiarativa seguente, contiene ItemTemplate
un controllo Web Image la cui ImageUrl
proprietà viene assegnata utilizzando la sintassi di associazione dati in base alle proprietà e ImageField DataImageUrlField
DataImageUrlFormatString
. Contiene EditItemTemplate
un controllo TextBox la cui Text
proprietà è associata al valore specificato dalla DataImageUrlField
proprietà .
<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>
È necessario aggiornare per EditItemTemplate
usare un controllo FileUpload. Dallo smart tag gridView fare clic sul collegamento Modifica modelli e quindi selezionare TemplateField Picture
dall'elenco EditItemTemplate
a discesa. Nel modello verrà visualizzato un controllo TextBox. Trascinare quindi un controllo FileUpload dalla casella degli strumenti nel modello, impostandone il ID
valore su PictureUpload
. Aggiungere anche il testo Per modificare l'immagine della categoria, specificare una nuova immagine. Per mantenere la stessa immagine della categoria, lasciare vuoto anche il campo al modello.
Figura 17: Aggiungere un controllo FileUpload a (fare clic per visualizzare l'immagineEditItemTemplate
a dimensione intera)
Dopo aver personalizzato l'interfaccia di modifica, visualizzare lo stato di avanzamento in un browser. Quando si visualizza una riga in modalità di sola lettura, l'immagine della categoria viene visualizzata come in precedenza, ma facendo clic sul pulsante Modifica la colonna immagine viene visualizzata come testo con un controllo FileUpload.
Figura 18: L'interfaccia di modifica include un controllo FileUpload (fare clic per visualizzare l'immagine a dimensione intera)
Tenere presente che ObjectDataSource è configurato per chiamare il CategoriesBLL
metodo della UpdateCategory
classe che accetta come input i dati binari per l'immagine come Byte
matrice. Se questa matrice è Nothing
, tuttavia, viene chiamato l'overload alternativo UpdateCategory
, che rilascia l'istruzione UPDATE
SQL che non modifica la Picture
colonna, lasciando invariata l'immagine corrente della categoria. Pertanto, nel gestore eventi di GridView è RowUpdating
necessario fare riferimento al PictureUpload
controllo FileUpload a livello di codice e determinare se è stato caricato un file. Se non ne è stato caricato uno, non si vuole specificare un valore per il picture
parametro . D'altra parte, se un file è stato caricato nel PictureUpload
controllo FileUpload, vogliamo assicurarsi che si tratti di un file JPG. In caso affermativo, è possibile inviare il contenuto binario a ObjectDataSource tramite il picture
parametro .
Analogamente al codice usato nel passaggio 6, gran parte del codice necessario qui esiste già nel gestore eventi di ItemInserting
DetailsView. Di conseguenza, è stato eseguito il refactoring delle funzionalità comuni in un nuovo metodo, ValidPictureUpload
e sono stati aggiornati il ItemInserting
gestore eventi per usare questo metodo.
Aggiungere il codice seguente all'inizio del gestore eventi di GridView.RowUpdating
È importante che questo codice venga prima del codice che salva il file della brochure perché non si vuole salvare la brochure nel file system del server Web se viene caricato un file immagine non valido.
' 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
Il ValidPictureUpload(FileUpload)
metodo accetta un controllo FileUpload come unico parametro di input e controlla l'estensione del file caricato per assicurarsi che il file caricato sia un file JPG. Viene chiamato solo se viene caricato un file immagine. Se non viene caricato alcun file, il parametro immagine non è impostato e quindi usa il valore predefinito di Nothing
. Se un'immagine è stata caricata e ValidPictureUpload
restituisce True
, al picture
parametro vengono assegnati i dati binari dell'immagine caricata; se il metodo restituisce False
, il flusso di lavoro di aggiornamento viene annullato e il gestore eventi è terminato.
Il codice del ValidPictureUpload(FileUpload)
metodo, che è stato sottoposto a refactoring dal gestore eventi detailsView, ItemInserting
segue:
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
Passaggio 8: Sostituzione delle immagini di categorie originali con JPG
Tenere presente che le otto categorie originali sono file bitmap di cui è stato eseguito il wrapping in un'intestazione OLE. Ora che è stata aggiunta la funzionalità per modificare un'immagine di un record esistente, è possibile sostituire queste bitmap con IPG. Se si desidera continuare a usare le immagini di categoria correnti, è possibile convertirle in JPG seguendo questa procedura:
- Salvare le immagini bitmap nel disco rigido. Visitare la
UpdatingAndDeleting.aspx
pagina nel browser e per ognuna delle prime otto categorie, fare clic con il pulsante destro del mouse sull'immagine e scegliere di salvare l'immagine. - Aprire l'immagine nell'editor di immagini preferito. Ad esempio, è possibile usare Microsoft Paint.
- Salvare la bitmap come immagine JPG.
- Aggiornare l'immagine della categoria tramite l'interfaccia di modifica, usando il file JPG.
Dopo aver modificato una categoria e caricato l'immagine JPG, l'immagine non verrà visualizzata nel browser perché la DisplayCategoryPicture.aspx
pagina rimuove i primi 78 byte dalle immagini delle prime otto categorie. Risolvere il problema rimuovendo il codice che esegue la rimozione dell'intestazione OLE. Dopo aver eseguito questa operazione, il DisplayCategoryPicture.aspx``Page_Load
gestore eventi deve avere solo il codice seguente:
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
Nota
L'inserimento UpdatingAndDeleting.aspx
e la modifica delle interfacce della pagina potrebbero usare un po' di più. I CategoryName
e Description
BoundFields in DetailsView e GridView devono essere convertiti in TemplateFields. Poiché CategoryName
non consente NULL
valori, è necessario aggiungere un oggetto RequiredFieldValidator. E il Description
controllo TextBox dovrebbe essere probabilmente convertito in un controllo TextBox a più righe. Lascio questi tocchi finali come esercizio per te.
Riepilogo
Questa esercitazione completa l'analisi dell'uso dei dati binari. In questa esercitazione e nelle tre precedenti è stato illustrato come i dati binari possono essere archiviati nel file system o direttamente all'interno del database. Un utente fornisce dati binari al sistema selezionando un file dal disco rigido e caricandolo nel server Web, in cui può essere archiviato nel file system o inserito nel database. ASP.NET 2.0 include un controllo FileUpload che consente di fornire un'interfaccia di questo tipo facile come il trascinamento della selezione. Tuttavia, come indicato nell'esercitazione Caricamento di file , il controllo FileUpload è adatto solo per caricamenti di file relativamente piccoli, idealmente non superare un megabyte. È stato anche illustrato come associare i dati caricati al modello di dati sottostante, nonché come modificare ed eliminare i dati binari dai record esistenti.
Il prossimo set di esercitazioni esplora varie tecniche di memorizzazione nella cache. La memorizzazione nella cache consente di migliorare le prestazioni complessive di un'applicazione prendendo i risultati da operazioni costose e archiviandoli in una posizione a cui è possibile accedere più rapidamente.
Buon programmatori!
Informazioni sull'autore
Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, disponibile all'indirizzo http://ScottOnWriting.NET.
Grazie speciale a
Questa serie di esercitazioni è stata esaminata da molti revisori utili. Il revisore principale di questa esercitazione era Teresa Murphy. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per