Condividi tramite


Aggiornamento ed eliminazione di dati binari esistenti (VB)

di Scott Mitchell

Scaricare 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 del Livello di Accesso ai Dati e del Livello di Logica di Business per lavorare con la colonna esistente Picture della tabella Categories, che contiene il contenuto binario dei file di immagine. Abbiamo creato pagine Web per presentare i dati binari in un GridView, con un collegamento di download per la brochure, e l'immagine della categoria mostrata in un elemento HTML <img>. Abbiamo aggiunto un controllo DetailsView per consentire agli utenti di aggiungere una nuova categoria e caricare la brochure e l'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 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 ha generato automaticamente i metodi Insert, Update e Delete, ma questi metodi sono stati generati in base alla query principale CategoriesTableAdapter, che non include la colonna Picture. Pertanto, i Insert metodi e Update non includono parametri per specificare i dati binari per l'immagine della categoria. Come 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 e scegliere Aggiungi Query dal menu di scelta rapida per avviare la Creazione guidata di configurazione 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 la generazione del tipo di query. Poiché si sta creando una query per aggiungere un nuovo record alla Categories tabella, scegliere AGGIORNA 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, che aggiorna i valori CategoryName, 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.

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 logico aziendale

Oltre ad aggiornare anche il DAL, è necessario aggiornare il BLL per includere i metodi per l'aggiornamento e la cancellazione di una categoria. Questi sono i metodi che verranno richiamati dal livello presentazione.

Per eliminare una categoria, è possibile usare il CategoriesTableAdapter metodo generato automaticamente Delete . 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, creiamo due metodi per l'aggiornamento di una categoria: uno che si aspetta i dati binari dell'immagine e richiama il metodo UpdateWithPicture appena aggiunto a CategoriesTableAdapter, e un altro che accetta solo i valori CategoryName, Description e BrochurePath e usa la classe CategoriesTableAdapter con un'istruzione Update generata automaticamente. La logica alla base dell'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 caricati possono quindi essere usati nell'istruzione UPDATE . In altri casi, l'utente potrebbe essere interessato solo ad aggiornare, per 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 viaggio al database per riportare i dati dell'immagine per il record da modificare. Pertanto, vogliamo due UPDATE metodi. Il livello di logica di business determinerà quale usare in base all'eventuale disponibilità di dati immagine durante l'aggiornamento della categoria.

Per semplificare 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; l'array Byte è destinato ai contenuti binari dell'immagine della categoria e Integer identifica il 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 gridView e ha fornito un controllo DetailsView per aggiungere nuove categorie al sistema. In questa esercitazione GridView verrà esteso per includere le funzionalità di modifica ed eliminazione. Invece di continuare a lavorare da UploadInDetailsView.aspx, inseriamo invece le modifiche di questo tutorial nella pagina UpdatingAndDeleting.aspx nella 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 quindi il markup all'interno del relativo <asp:Content> elemento. Analogamente, copiare il codice dalla classe code-behind della pagina UploadInDetailsView.aspx in 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, vai su UpdatingAndDeleting.aspx. Dovrebbe essere visualizzato lo stesso output e avere la stessa esperienza utente come con la pagina UploadInDetailsView.aspx del tutorial 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 di 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. L'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 l'uso con la CategoriesBLL classe . Premere Avanti. Attualmente, sono specificate solo le proprietà InsertMethod s e SelectMethod di ObjectDataSource. Tuttavia, la procedura guidata ha popolato automaticamente gli elenchi a discesa nelle schede UPDATE e DELETE con i metodi UpdateCategory e DeleteCategory, rispettivamente. Ciò è perché nella classe CategoriesBLL abbiamo contrassegnato 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 della scheda DELETE 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 (DeleteCategory a dimensione intera)

Annotazioni

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é scegliendo Sì si sovrascriveranno 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à OldValuesParameterFormatStringObjectDataSource su original_{0} , che causa problemi con le chiamate al metodo update ed delete. Pertanto, cancellare completamente questa proprietà o reimpostarla sull'impostazione predefinita, {0}. Se è necessario rinfrescare la memoria su questa proprietà ObjectDataSource, vedere l'esercitazione Panoramica sull'inserimento, l'aggiornamento e l'eliminazione di dati.

Dopo aver corretto OldValuesParameterFormatString e completato la procedura guidata, il markup dichiarativo di ObjectDataSource dovrebbe assomigliare 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 gridView. Verrà aggiunto un oggetto 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)

Prenditi un momento per provare 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 l'esplora soluzioni. Ora dovresti vedere un nuovo file nella cartella ~/Brochures, Test.pdf (vedi Figura 8).

Quindi, fai clic sul collegamento Elimina nella riga Categoria di test, provocando il postback della pagina e attivando la classe CategoriesBLL e il metodo DeleteCategory. Verrà richiamato il metodo del DAL Delete, causando l'invio dell'istruzione appropriata DELETE al database. I dati vengono quindi riassociati a GridView e il codice viene inviato nuovamente al client con la Categoria di test non più presente.

Anche se il flusso di lavoro di eliminazione ha rimosso correttamente il record di Categoria di Test dalla Categories tabella, il file della brochure non è stato rimosso dal file system del server web. Aggiorna Esplora soluzioni e noterai che Test.pdf è ancora presente nella cartella ~/Brochures.

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 brochure della categoria eliminata

Uno degli aspetti negativi dell'archiviazione di dati binari esterni al database è che è necessario eseguire ulteriori passaggi per pulire questi file quando il record di database associato viene eliminato. GridView e ObjectDataSource forniscono eventi che vengono attivati sia prima che dopo l'esecuzione del comando delete. In realtà è necessario creare i gestori degli eventi per gli eventi di pre-azione 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 viene eliminata.

L'evento gridView RowDeleting viene generato prima che sia stato richiamato il comando delete di 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

Nel gestore eventi RowDeleting, l' CategoryID della riga da eliminare viene ottenuto dalla raccolta DataKeys di GridView, accessibile in questo gestore eventi tramite la raccolta e.Keys. Viene quindi richiamata la CategoriesBLL classe s GetCategoryByCategoryID(categoryID) per restituire informazioni sul record da eliminare. Se l'oggetto restituito CategoriesDataRow ha un valore non-NULL``BrochurePath, viene archiviato nella variabile della pagina deletedCategorysPdfPath in modo che il file possa essere eliminato nel gestore eventi RowDeleted.

Annotazioni

Anziché recuperare i BrochurePath dettagli per il Categories record eliminato nel RowDeleting gestore eventi, in alternativa potremmo aggiungere il BrochurePath alla proprietà DataKeyNames di GridView e accedere al valore del record tramite la raccolta e.Keys. In questo modo si aumentano leggermente le dimensioni dello stato di visualizzazione di GridView, ma si riduce la quantità di codice necessaria e si salva un viaggio nel database.

Dopo aver richiamato il comando delete sottostante di ObjectDataSource, viene attivato il gestore eventi di RowDeleted GridView. Se non sono state rilevate 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. Poiché i dati dell'immagine vengono archiviati direttamente nel database, 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 alcune problematiche interessanti. La parte restante di questa esercitazione illustra l'aggiunta di 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 sull'inserimento, l'aggiornamento e l'eliminazione di dati, GridView offre il supporto predefinito per la modifica a livello di riga che può essere implementato dal segno di spunta di una casella di controllo se l'origine dati sottostante è configurata in modo appropriato. Attualmente ObjectDataSource CategoriesDataSource non è ancora configurato per includere il supporto per l'aggiornamento, quindi è possibile aggiungerlo.

Fare clic sul collegamento Configura origine dati dalla procedura guidata ObjectDataSource e procedere con il secondo passaggio. A causa dell'elemento DataObjectMethodAttribute usato in CategoriesBLL, l'elenco a discesa UPDATE deve essere popolato automaticamente con l'overload UpdateCategory che accetta quattro parametri di input (tranne Picture). Modificare questa impostazione in modo che usi l'overload con cinque parametri.

Configurare ObjectDataSource per l'utilizzo del metodo UpdateCategory che include un parametro per l'immagine

Figura 9: Configurare ObjectDataSource per l'uso del UpdateCategory metodo che include un parametro per Picture (fare clic per visualizzare l'immagine a dimensione intera)

ObjectDataSource includerà ora un valore per la relativa UpdateMethod proprietà, nonché i valori corrispondenti UpdateParameter . Come indicato nel passaggio 4, Visual Studio imposta la proprietà OldValuesParameterFormatString ObjectDataSource su original_{0} quando si usa la procedura guidata Configura origine dati. Ciò causerà problemi con le chiamate al metodo update ed delete. Pertanto, cancellare completamente questa proprietà o reimpostarla sull'impostazione predefinita, {0}.

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" 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 gridView. Verrà impostata la proprietà ShowEditButtonCommandField su True , con conseguente aggiunta di un pulsante Modifica (e 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 dimensione intera)

Visitare la pagina tramite un browser e fare clic su uno dei pulsanti Modifica della riga. Il CategoryName e il Description BoundFields sono visualizzati come caselle di testo. Il TemplateField BrochurePath manca di un EditItemTemplate, quindi continua a mostrare ItemTemplate un collegamento alla brochure. ImageField Picture esegue il rendering come TextBox la cui proprietà Text viene assegnata al valore della proprietà DataImageUrlField di ImageField, in questo caso CategoryID.

GridView non dispone di un'interfaccia di modifica per BrochurePath

Figura 11: GridView non dispone di un'interfaccia di modifica per BrochurePath (fare clic per visualizzare l'immagine a dimensione intera)

Personalizzazione dell'interfacciaBrochurePathdi modifica

È necessario creare un'interfaccia di modifica per BrochurePath TemplateField, una che consente all'utente di:

  • Lascia la brochure della categoria as-is,
  • 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).

Dobbiamo anche aggiornare l'interfaccia di modifica di Picture ImageField, ma ci occuperemo di questo nel passaggio 7.

Dallo smart tag di GridView, fai clic sul collegamento Modifica modelli e seleziona il campo Template BrochurePath dal menu a tendina EditItemTemplate. Aggiungere un controllo Web RadioButtonList a questo modello, impostandone la ID proprietà su BrochureOptions e la relativa AutoPostBack proprietà su True. Nella finestra Proprietà, fare clic sul puntino di sospensione nella proprietà Items, che aprirà l'Editor della raccolta ListItem. Aggiungere le tre opzioni seguenti rispettivamente con Value s 1, 2 e 3:

  • Utilizzare la brochure corrente
  • Rimuovere la brochure corrente
  • Caricare una nuova brochure

Impostare la prima proprietà ListItem su Selected.

Aggiungere tre elementi ListItem all'oggetto RadioButtonList

Figura 12: Aggiungere tre elementi al RadioButtonList

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

Aggiungere un controllo RadioButtonList e FileUpload a EditItemTemplate

Figura 13: Aggiungere un controllo RadioButtonList e FileUpload al EditItemTemplate (fare clic per visualizzare l'immagine a dimensione intera)

Questo RadioButtonList fornisce le tre opzioni per l'utente. L'idea è che il controllo FileUpload verrà visualizzato solo se è selezionata l'ultima opzione Carica nuova brochure. A tale 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 po' di codice per accedere a questi controlli a livello di codice. Al SelectedIndexChanged gestore eventi viene passato un riferimento di RadioButtonList nel sender parametro di input. Per ottenere il controllo FileUpload, è necessario ottenere il controllo padre di RadioButtonList e usare il metodo FindControl("controlID") da lì. Dopo aver ottenuto un riferimento ai controlli RadioButtonList e FileUpload, la proprietà del controllo Visible FileUpload è impostata su True solo se il valore di RadioButtonList è SelectedValue uguale a 3, che rappresenta il caricamento di una nuova brochure Value.

Con questo codice in atto, prenditi un momento per provare l'interfaccia di modifica. Fare clic sul pulsante Modifica per una riga. Inizialmente, l'opzione Usa brochure corrente dovrebbe essere selezionata. La modifica dell'indice selezionato causa un postback. Se è selezionata la terza opzione, viene visualizzato il controllo FileUpload, altrimenti è nascosto. La figura 14 mostra l'interfaccia di modifica quando si fa clic sul pulsante Modifica; La figura 15 mostra l'interfaccia dopo l'opzione Carica nuova brochure selezionata.

Inizialmente, l'opzione Usa la brochure corrente è selezionata

Figura 14: Inizialmente, l'opzione Usa brochure corrente è selezionata (fare clic per visualizzare l'immagine a dimensione intera)

Se si sceglie l'opzione Carica nuova brochure, viene visualizzato il controllo FileUpload

Figura 15: Scelta dell'opzione Carica nuova brochure Visualizza il controllo FileUpload (fare clic per visualizzare l'immagine a dimensione intera)

Salvataggio del file della brochure e aggiornamento dellaBrochurePathcolonna

Quando si fa clic sul pulsante Update di GridView, viene generato il relativo RowUpdating evento. Il comando di aggiornamento di ObjectDataSource viene richiamato e quindi viene generato l'evento GridView.RowUpdated Analogamente al flusso di lavoro di eliminazione, è necessario creare gestori eventi per entrambi questi eventi. Nel gestore eventi RowUpdating, è necessario determinare l'azione da intraprendere in base allo stato di SelectedValue del BrochureOptions 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 da aggiornare. Il parametro s brochurePath ObjectDataSource può essere impostato tramite 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 brochurePathNothing, che comporta l'uso di un database NULL nell'istruzione UPDATE. Se è presente un file brochure esistente che viene rimosso, è 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 da completare 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. Pertanto, è opportuno rifattorizzare questa funzionalità suddividendola 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 della pagina deletedCategorysPdfPath se deletedCategorysPdfPath non è null.

Di seguito è riportato il codice per questi due metodi. Si noti la somiglianza tra ProcessBrochureUpload e il gestore degli eventi di ItemInserting del DetailsView della lezione 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 apportate ai gestori eventi di 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 gridView RowUpdating usano i RowUpdated metodi e ProcessBrochureUploadDeleteRememberedBrochurePath , come illustrato nel codice 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 in uso, è possibile modificare una categoria e usare la sua brochure attuale, non utilizzare la brochure o caricarne una nuova. Vai avanti e provalo. Imposta i punti di interruzione nei gestori degli eventi RowUpdating e RowUpdated per ottenere un'idea del flusso di lavoro.

Passaggio 7: Caricamento di una nuova immagine

L'interfaccia di modifica di Picture ImageField viene visualizzata come una casella di testo che appare popolata con il valore della sua proprietà DataImageUrlField. 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, sostituisce il valore sottostante CategoryID del parametro CategoryID con quello della riga corrente, ovvero 10. In breve, l'interfaccia di modifica di ImageField non influisce sul flusso di lavoro di modifica per questa esercitazione perché i nomi della proprietà di ImageField e il valore della griglia DataImageUrlField sono lo 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 abbiamo deciso di richiedere che ogni categoria debba avere un'immagine. Pertanto, non è necessario consentire all'utente di indicare che non esiste un'immagine associata che l'utente può caricare una nuova immagine o lasciare l'immagine corrente as-is.

Per personalizzare l'interfaccia di modifica di ImageField, è necessario convertirla in un oggetto TemplateField. Dallo smart tag di GridView, fare clic sul collegamento Modifica colonne, selezionare ImageField e fare clic sul collegamento Converti questo campo in un campo Template.

Convertire l'ImageField in un TemplateField

Figura 16: Convertire imageField in un campo modello

La conversione di ImageField in un oggetto TemplateField in questo modo genera un oggetto TemplateField con due modelli. Come illustrato nella sintassi dichiarativa seguente, ItemTemplate contiene un controllo Web Image, la cui proprietà ImageUrl viene assegnata usando la sintassi di associazione dati basata sulle proprietà DataImageUrlField e DataImageUrlFormatString di ImageField. EditItemTemplate contiene una TextBox il cui Text è associato al valore specificato dalla proprietà DataImageUrlField.

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

È necessario aggiornare il EditItemTemplate per usare un controllo FileUpload. Dallo smart tag GridView, fare clic sul collegamento Modifica modelli e quindi selezionare Picture dalla lista a discesa TemplateField EditItemTemplate. Nel modello dovrebbe essere visualizzato un controllo TextBox, rimuovilo. Successivamente, trascina un controllo FileUpload dalla casella degli strumenti nel modello e imposta la sua proprietà ID su PictureUpload. Aggiungere anche il testo Per modificare l'immagine della categoria, specificare una nuova immagine. Per mantenere invariata l'immagine della categoria, lascia vuoto anche il campo nel modello.

Aggiungere un controllo FileUpload a EditItemTemplate

Figura 17: Aggiungere un controllo FileUpload a EditItemTemplate (fare clic per visualizzare l'immagine 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 mostrata come prima, ma facendo clic sul pulsante Modifica la colonna dell'immagine viene visualizzata come testo con un controllo di caricamento file.

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 esegue l'istruzione SQL UPDATE che non modifica la colonna Picture, mantenendo così intatta l'immagine corrente della categoria. Pertanto, nel gestore eventi di RowUpdating GridView è necessario fare riferimento a livello di codice al PictureUpload controllo FileUpload e determinare se è stato caricato un file. Se non è stato caricato, non desideriamo specificare un valore per il parametro picture. 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 relativo contenuto binario a ObjectDataSource tramite il picture parametro .

Analogamente al codice usato nel passaggio 6, gran parte del codice necessario esiste già nel gestore eventi di ItemInserting DetailsView. Di conseguenza, ho refattorizzato le funzionalità comuni in un nuovo metodo, ValidPictureUpload e ho aggiornato il ItemInserting gestore eventi per usare questo metodo.

Aggiungere il codice seguente all'inizio del gestore eventi di RowUpdating GridView. È 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 jpg; viene chiamato solo se viene caricato un file immagine. Se non viene caricato alcun file, il parametro picture 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 refactorizzato dal gestore eventi di ItemInserting DetailsView, è il seguente.

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 delle categorie originali con JPG

Tenere presente che le immagini delle otto categorie originali sono file bitmap avvolte in un'intestazione OLE. Ora che è stata aggiunta la funzionalità per modificare un'immagine di un record esistente, prenditi un momento per sostituire queste bitmap con JPG. 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 questo 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

Annotazioni

Le interfacce di inserimento e modifica della pagina UpdatingAndDeleting.aspx necessitano di qualche miglioramento. I CategoryName e Description BoundFields in DetailsView e GridView devono essere convertiti in TemplateFields. Poiché CategoryName non consente valori NULL , è necessario aggiungere un oggetto RequiredFieldValidator. E il Description TextBox dovrebbe essere probabilmente convertito in un TextBox a più righe. Lascio questi ritocchi finali come esercizio per te.

Riassunto

Questa esercitazione completa l'analisi dell'uso dei dati binari. In questa esercitazione e nelle tre precedenti è stato illustrato come archiviare i dati binari 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 rende facile fornire un'interfaccia del genere tramite trascinamento e rilascio. Tuttavia, come indicato nell'esercitazione Caricamento di file, il controllo FileUpload è adatto solo per caricamenti di file relativamente piccoli, idealmente senza 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, ha lavorato 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 a mitchell@4GuysFromRolla.com.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori competenti. Il revisore principale di questo tutorial è stata Teresa Murphy. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.