Aggiornamento ed eliminazione di dati binari esistenti (VB)

di Scott Mitchell

Scarica il PDF

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 Insertmetodi , Updatee 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.

Selezionare l'opzione UPDATE

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 CategoryNamevalori , Descriptione 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.

Denominare il nuovo metodo TableAdapter UpdateWithPicture

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 CategoryNamevalori , Descriptione 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.

Copiare il markup dichiarativo da UploadInDetailsView.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.

Configurare ObjectDataSource per l'utilizzo del metodo DeleteCategory

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.

Abilitare il supporto per l'eliminazione in GridView

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.

Aggiungere una categoria di test con una brochure e un'immagine

Figura 6: Aggiungere una categoria di test con una brochure e un'immagine (fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver inserito la categoria di test, viene visualizzata in GridView

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.

Il file Test.pdf non è stato eliminato dal file system del server Web

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 DataObjectMethodAttributeUpdateCategory 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.

Configurare ObjectDataSource per usare il metodo UpdateCategory che include un parametro per l'immagine

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à TrueCommandField su ShowEditButton , che comporta l'aggiunta di un pulsante Modifica (e i pulsanti Aggiorna e Annulla per la riga da modificare).

Configurare GridView per supportare la modifica

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 EditItemTemplateoggetto , 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.

GridView manca di un'interfaccia di modifica per BrochurePath

Figura 11: GridView manca di un'interfaccia di modifica per BrochurePath (fare clic per visualizzare l'immagine a dimensioni complete)

Personalizzazione dell'interfacciaBrochurePathdi 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à Truesu Selected .

Aggiungere Tre listItems all'elenco RadioButtonList

Figura 12: Aggiungere tre ListItem s all'elenco RadioButtonList

Sotto radioButtonList aggiungere un controllo FileUpload denominato BrochureUpload. Impostare la proprietà Visible su False.

Aggiungere un controllo RadioButtonList e FileUpload all'oggetto EditItemTemplate

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.

Inizialmente, l'opzione Use current brochure è selezionata

Figura 14: Inizialmente, l'opzione Use current brochure è selezionata (Fare clic per visualizzare l'immagine a dimensioni complete)

Scegliere l'opzione Carica nuova brochure Visualizza il controllo FileUpload

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 dellaBrochurePathcolonna

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 SelectedValueBrochureOptions RadioButtonList:

  • Se è SelectedValue 1, si vuole continuare a usare la stessa BrochurePath impostazione. È quindi necessario impostare il parametro ObjectDataSource sul brochurePath valore esistente BrochurePath del record aggiornato. Il parametro ObjectDataSource s brochurePath può essere impostato usando e.NewValues["brochurePath"] = value.
  • Se è SelectedValue 2, si vuole impostare il valore del BrochurePath record su NULL. Questa operazione può essere eseguita impostando il parametro ObjectDataSource su brochurePath , che comporta l'uso di un database NULL nell'istruzione UPDATE .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 del BrochurePath 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 o null se non è stato salvato alcun file.
  • DeleteRememberedBrochurePath elimina il file specificato dal percorso nella variabile deletedCategorysPdfPath di pagina se deletedCategorysPdfPath non nullè .

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).

Convertire imagefield 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 DataImageUrlFieldDataImageUrlFormatString . 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.

Aggiungere un controllo FileUpload a EditItemTemplate

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.

L'interfaccia di modifica include 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, ValidPictureUploade 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:

  1. 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.
  2. Aprire l'immagine nell'editor di immagini preferito. Ad esempio, è possibile usare Microsoft Paint.
  3. Salvare la bitmap come immagine JPG.
  4. 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.