Sdílet prostřednictvím


Aktualizace a odstranění stávajících binárních dat (VB)

od Scott Mitchell

Stáhnout PDF

V předchozích kurzech jsme viděli, jak ovládací prvek GridView usnadňuje úpravy a odstranění textových dat. V tomto kurzu vidíme, jak ovládací prvek GridView umožňuje také upravovat a odstraňovat binární data, ať už jsou tato binární data uložena v databázi nebo uložena v systému souborů.

Úvod

V posledních třech kurzech jsme přidali poměrně hodně funkcí pro práci s binárními daty. Začali jsme přidáním BrochurePath sloupce do Categories tabulky a odpovídajícím způsobem jsme aktualizovali architekturu. Přidali jsme také metody vrstvy přístupu k datům a vrstvy obchodní logiky pro práci se stávajícím Picture sloupcem tabulky Categories, která obsahuje binární obsah souboru obrázku. Vytvořili jsme webové stránky pro prezentaci binárních dat v GridView odkaz ke stažení brožury, s obrázkem kategorie zobrazeným v elementu <img> a přidali jsme DetailsView, aby uživatelé mohli přidat novou kategorii a nahrát její brožuru a data obrázků.

Vše, co je potřeba implementovat, je schopnost upravovat a odstraňovat existující kategorie, které v tomto kurzu provedeme pomocí předdefinovaných funkcí pro úpravy a odstraňování GridView. Při úpravě kategorie bude uživatel moct volitelně nahrát nový obrázek nebo bude mít kategorii dál používat stávající. U brožury se můžou rozhodnout použít stávající brožuru, nahrát novou brožuru nebo určit, že kategorie už k ní nemá přidruženou brožuru. Pojďme začít!

Krok 1: Aktualizace vrstvy přístupu k datům

Dal má automaticky vygenerované Insert, Update a Delete metody, ale tyto metody byly generovány na základě hlavního dotazu CategoriesTableAdapter, který neobsahuje sloupec Picture. Proto metody Insert a Update nezahrnují parametry pro určení binárních dat obrázku kategorie. Stejně jako v předchozím kurzu potřebujeme vytvořit novou metodu TableAdapter pro aktualizaci Categories tabulky při zadávání binárních dat.

Otevřete Typovou datovou sadu a v Návrháři klikněte pravým tlačítkem myši na CategoriesTableAdapter záhlaví s a v místní nabídce zvolte Přidat dotaz a spusťte Průvodce konfigurací dotazu TableAdapter. Tento průvodce začíná dotazem, jak má dotaz TableAdapter přistupovat k databázi. Zvolte Použít příkazy SQL a klikněte na Další. V dalším kroku se zobrazí výzva k vygenerování typu dotazu. Vzhledem k tomu, že vytváříme dotaz pro přidání nového záznamu Categories do tabulky, zvolte AKTUALIZOVAT a klikněte na Další.

Vyberte možnost AKTUALIZOVAT.

Obrázek 1: Vyberte možnost AKTUALIZOVAT (kliknutím zobrazíte obrázek s plnou velikostí)

Teď musíme zadat UPDATE příkaz SQL. Průvodce automaticky navrhne UPDATE příkaz odpovídající hlavnímu dotazu TableAdapter (ten, který aktualizuje CategoryName, Descriptiona BrochurePath hodnoty). Změňte příkaz tak, aby byl sloupec Picture zahrnutý spolu s parametrem @Picture, například takto:

UPDATE [Categories] SET 
    [CategoryName] = @CategoryName, 
    [Description] = @Description, 
    [BrochurePath] = @BrochurePath ,
    [Picture] = @Picture
WHERE (([CategoryID] = @Original_CategoryID))

Poslední obrazovka průvodce nás požádá o pojmenování nové metody TableAdapter. Zadejte UpdateWithPicture a klikněte na Dokončit.

Pojmenujte novou metodu TableAdapter UpdateWithPicture

Obrázek 2: Pojmenování metody UpdateWithPicture New TableAdapter (kliknutím zobrazíte obrázek v plné velikosti)

Krok 2: Přidání metod vrstvy obchodní logiky

Kromě aktualizace DAL musíme aktualizovat BLL tak, aby zahrnoval metody aktualizace a odstranění kategorie. Jedná se o metody, které budou vyvolány z prezentační vrstvy.

K odstranění kategorie můžeme použít CategoriesTableAdapter automaticky vygenerovanou Delete metodu. Do třídy přidejte následující metodu 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

Pro účely tohoto kurzu vytvoříme dvě metody pro aktualizaci kategorie – jedna, která očekává data binárního obrázku a vyvolá metodu UpdateWithPicture, kterou jsme právě přidali do CategoriesTableAdapter, a druhá, která přijímá pouze hodnoty CategoryName, Description, a BrochurePath a používá automaticky generovaný příkaz třídy CategoriesTableAdapterUpdate. Důvodem použití dvou metod je, že za určitých okolností může uživatel chtít aktualizovat obrázek kategorie spolu s dalšími poli, v takovém případě bude muset uživatel nový obrázek nahrát. Nahraná binární data obrázku se pak dají použít v příkazu UPDATE. V jiných případech by se uživatel mohl zajímat pouze o aktualizaci, například pouze názvu a popisu. Pokud ale příkaz UPDATE očekává binární data pro sloupec Picture také, musíme tyto informace poskytnout. To by vyžadovalo další dotaz do databáze, aby byla načtena data obrázku pro upravovaný záznam. Proto chceme dvě UPDATE metody. Vrstva obchodní logiky určí, který má být použit, podle toho, zda jsou při aktualizaci kategorie poskytnuta data obrázku.

Chcete-li to usnadnit, přidejte dvě metody do CategoriesBLL třídy, obě pojmenované UpdateCategory. První by měl přijmout tři String s, Byte pole a Integer jako vstupní parametry; druhý, jen tři String a a Integer. Vstupní String parametry jsou určené pro název kategorie, popis a cestu k souboru brožury, Byte pole je určené pro binární obsah obrázku kategorie a Integer identifikuje CategoryID záznam, který se má aktualizovat. Všimněte si, že první přetížení vyvolá druhé Byte, pokud je předané pole 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

Krok 3: Kopírování funkce vložení a zobrazení

V předchozím kurzu jsme vytvořili stránku s názvem UploadInDetailsView.aspx , která obsahuje všechny kategorie v GridView a poskytli DetailsView pro přidání nových kategorií do systému. V tomto kurzu rozšíříme Objekt GridView tak, aby zahrnoval podporu úprav a odstraňování. Místo pokračování v práci z UploadInDetailsView.aspx umístíme změny z tohoto kurzu na stránku UpdatingAndDeleting.aspx ve stejné složce, ~/BinaryData. Zkopírujte a vložte deklarativní kód a kód z UploadInDetailsView.aspx do UpdatingAndDeleting.aspx.

Začněte otevřením UploadInDetailsView.aspx stránky. Zkopírujte všechny deklarativní syntaxe uvnitř elementu <asp:Content> , jak je znázorněno na obrázku 3. Dále otevřete UpdatingAndDeleting.aspx a vložte tento kód do jeho <asp:Content> prvku. Podobně zkopírujte kód z třídy code-behind stránky UploadInDetailsView.aspx do UpdatingAndDeleting.aspx.

Zkopírujte deklarativní kód z UploadInDetailsView.aspx

Obrázek 3: Zkopírovat deklarativní značkování z UploadInDetailsView.aspx (kliknutím zobrazíte obrázek v plné velikosti)

Po zkopírování deklarativního označení a kódu navštivte UpdatingAndDeleting.aspx. Měli byste vidět stejný výstup a mít stejné uživatelské prostředí jako stránka UploadInDetailsView.aspx z předchozího kurzu.

Krok 4: Přidání podpory odstranění do ObjectDataSource a GridView

Jak jsme si probrali zpět v kurzu Vložení, aktualizace a odstranění dat , poskytuje GridView integrované možnosti odstraňování a tyto možnosti je možné povolit na zaškrtnutí políčka, pokud podkladový zdroj dat mřížky podporuje odstranění. V současné době objekt ObjectDataSource, ke kterému je GridView vázán (CategoriesDataSource), nepodporuje odstraňování.

Chcete-li tento problém napravit, klikněte na možnost Konfigurovat zdroj dat z inteligentní značky ObjectDataSource, abyste spustili průvodce. První obrazovka ukazuje, že ObjectDataSource je nakonfigurován pro práci s CategoriesBLL třídou. Stiskněte další. V současné době jsou zadány pouze vlastnosti ObjectDataSource InsertMethod a SelectMethod. Průvodce však automaticky naplnil rozevírací seznamy na kartách UPDATE a DELETE metodami UpdateCategory a DeleteCategory. Je to proto, že ve CategoriesBLL třídě jsme tyto metody označili jako DataObjectMethodAttribute výchozími metodami pro aktualizaci a odstranění.

Prozatím nastavte rozevírací seznam karty UPDATE na (Žádné), ale ponechte rozevírací seznam karty DELETE nastavený na DeleteCategory. K tomuto průvodci se vrátíme v kroku 6 a přidáme podporu aktualizace.

Konfigurace ObjectDataSource pro použití DeleteCategory – metoda

Obrázek 4: Konfigurace ObjectDataSource pro použití DeleteCategory metody (kliknutím zobrazíte obrázek v plné velikosti)

Poznámka:

Po dokončení průvodce se vás Visual Studio může zeptat, jestli chcete aktualizovat pole a klíče, což znovu vygeneruje pole ovládacích prvků datových webů. Zvolte Ne, protože když zvolíte Ano, přepíšete všechna vlastní nastavení polí, která jste udělali.

ObjectDataSource nyní bude obsahovat hodnotu pro jeho DeleteMethod vlastnost a také DeleteParameter. Pamatujte, že při použití průvodce k určení metod Visual Studio nastaví vlastnost objektu ObjectDataSource na OldValuesParameterFormatString, což způsobuje problémy s metodami pro aktualizaci a mazání. Proto buď tuto vlastnost úplně vymažte, nebo obnovit na výchozí , {0}. Pokud potřebujete aktualizovat paměť u této vlastnosti ObjectDataSource, prohlédněte si kurz o vkládání, aktualizaci a odstraňování dat .

Po dokončení průvodce a opravě OldValuesParameterFormatStringdeklarativního kódu ObjectDataSource by měl vypadat podobně jako následující:

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

Po dokončení konfigurace ObjectDataSource přidejte do GridView funkci odstranění zaškrtnutím políčka "Povolit odstranění" z inteligentní značky GridView. Tím přidáte CommandField do GridView, jehož ShowDeleteButton vlastnost je nastavena na True.

Povolení podpory pro odstranění v GridView

Obrázek 5: Povolení podpory pro odstranění v objektu GridView (kliknutím zobrazíte obrázek s plnou velikostí)

Chvíli vyzkoušejte funkci odstranění. Mezi tabulkami Products a CategoryID a tabulkami Categories a CategoryID existuje cizí klíč, takže pokud se pokusíte odstranit některou z prvních osmi kategorií, obdržíte výjimku z důvodu porušení omezení cizího klíče. Pokud chcete tuto funkci otestovat, přidejte novou kategorii, která poskytuje brožuru i obrázek. Moje testovací kategorie zobrazená na obrázku 6 obsahuje soubor testovací brožury s názvem Test.pdf a testovací obrázek. Obrázek 7 znázorňuje GridView po přidání testovací kategorie.

Přidání testovací kategorie s brožurou a obrázkem

Obrázek 6: Přidání testovací kategorie s brožurou a obrázkem (kliknutím zobrazíte obrázek v plné velikosti)

Po vložení kategorie testu se zobrazí v objektu GridView.

Obrázek 7: Po vložení kategorie testu se zobrazí v Objektu GridView (kliknutím zobrazíte obrázek v plné velikosti).

V sadě Visual Studio aktualizujte Průzkumníka řešení. Ve složce ~/Brochures by se teď měl zobrazit nový soubor Test.pdf (viz obrázek 8).

Dále klikněte na odkaz Delete v řádku Test Category, což způsobí, že stránka postback a CategoriesBLL metoda třídy s DeleteCategory se aktivuje. Tím se vyvolá metoda DAL s Delete , což způsobí odeslání příslušného DELETE příkazu do databáze. Data se pak znovu naváže na GridView a značky jsou odeslány zpět klientovi bez přítomnosti testovací kategorie.

I když pracovní postup odstranění úspěšně odebral záznam Kategorie testu z Categories tabulky, neodebral soubor brožury ze systému souborů webového serveru. Aktualizujte Průzkumníka řešení a uvidíte, že Test.pdf se stále nachází ve ~/Brochures složce.

Soubor Test.pdf nebyl odstraněn ze systému souborů webového serveru.

Obrázek 8: Test.pdf Soubor nebyl odstraněn ze systému souborů webového serveru

Krok 5: Odebrání souboru brožury kategorie Deleted

Jednou z nevýhod ukládání binárních dat mimo databázi je, že při odstranění přidruženého záznamu databáze je potřeba provést další kroky k vyčištění těchto souborů. GridView a ObjectDataSource poskytují události, které se aktivovaly před a po provedení příkazu delete. Ve skutečnosti potřebujeme vytvořit obslužné rutiny událostí pro události před akcí i po akci. Před odstraněním záznamu Categories musíme určit cestu k souboru PDF, ale nechceme odstranit PDF před odstraněním kategorie v případě, že dojde k nějaké výjimce a kategorie se neodstraní.

Událost GridView se RowDeleting aktivuje před vyvoláním příkazu delete u ObjectDataSource, zatímco jeho RowDeleted událost se aktivuje po. Pomocí následujícího kódu vytvořte obslužné rutiny událostí pro tyto dvě události:

' 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

V obslužné rutině RowDeletingCategoryID události se odstraněný řádek vezme z kolekce GridView s DataKeys , ke které lze přistupovat v této obslužné rutině e.Keys události prostřednictvím kolekce. Dále je vyvolána třída CategoriesBLLGetCategoryByCategoryID(categoryID), která vrátí informace o odstraňovaném záznamu. Pokud má vrácený CategoriesDataRow objekt nenulovou NULL``BrochurePath hodnotu, tak se uloží do proměnné deletedCategorysPdfPath stránky, aby mohl být soubor odstraněn při obsluze události RowDeleted.

Poznámka:

Namísto načítání BrochurePath podrobností pro Categories záznam, který byl odstraněn v RowDeleting obslužné rutině události, mohli jsme místo toho přidat BrochurePath do vlastnosti DataKeyNames GridView a přistupovat k hodnotě záznamu prostřednictvím e.Keys kolekce. Tímto způsobem by se velikost stavu zobrazení GridView mírně zvětšovala, ale snížila by množství potřebného kódu a ušetřila by cestu do databáze.

Po vyvolání základního příkazu pro odstranění v ObjectDataSource se aktivuje obslužná rutina události GridView RowDeleted. Pokud při odstraňování dat nedošlo k žádným výjimkám a existuje hodnota deletedCategorysPdfPath, soubor PDF se odstraní ze systému souborů. Všimněte si, že tento dodatečný kód není potřeba k vyčištění binárních dat kategorií přidružených k jeho obrázku. Důvodem je to, že data obrázku jsou uložená přímo v databázi, takže odstraněním Categories řádku odstraníte také data obrázku dané kategorie.

Po přidání dvou obslužných rutin událostí spusťte tento testovací případ znovu. Při odstraňování kategorie se odstraní také přidružený soubor PDF.

Aktualizace existujících binárních dat přidružených k záznamům přináší některé zajímavé výzvy. Zbývající část tohoto kurzu se zaměřuje na přidání možností aktualizace do brožury a obrázků. Krok 6 zkoumá techniky aktualizace informací o brožurě, zatímco krok 7 sleduje aktualizaci obrázku.

Krok 6: Aktualizace brožury kategorie

Jak je popsáno v kurzu Vložení, aktualizace a odstranění dat, GridView nabízí integrovanou podporu úprav na úrovni řádků, kterou lze implementovat zaškrtnutím políčka, pokud je jeho podkladový zdroj dat správně nakonfigurovaný. Objekt ObjectDataSource zatím není nakonfigurovaný tak, CategoriesDataSource aby zahrnoval podporu aktualizace, takže ji pojďme přidat.

Klikněte na odkaz Konfigurovat zdroj dat v průvodci ObjectDataSource a přejděte k druhému kroku. Vzhledem k použití DataObjectMethodAttribute v CategoriesBLL by měl být aktualizační rozevírací seznam automaticky naplněn přetížením UpdateCategory, které přijímá čtyři vstupní parametry (pro všechny sloupce kromě Picture). Změňte to tak, aby používalo přetížení s pěti parametry.

Konfigurujte ObjectDataSource pro použití metody UpdateCategory, která zahrnuje parametr pro obrázek.

Obrázek 9: Konfigurace ObjectDataSource pro použití UpdateCategory metody, která zahrnuje parametr (Picturekliknutím zobrazíte obrázek s plnou velikostí)

ObjectDataSource teď bude obsahovat hodnotu pro svou UpdateMethod vlastnost a také odpovídající UpdateParameter hodnoty. Jak je uvedeno v kroku 4, Visual Studio nastaví vlastnost ObjectDataSource OldValuesParameterFormatString na original_{0} při použití průvodce konfigurace zdroje dat. To způsobí problémy s vyvoláním metody aktualizace a odstranění. Proto buď tuto vlastnost úplně vymažte, nebo obnovit na výchozí , {0}.

Po dokončení průvodce a opravení OldValuesParameterFormatStringdeklarativního kódu ObjectDataSource by měl vypadat takto:

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

Pokud chcete zapnout vestavěné funkce pro úpravy GridView, zaškrtněte možnost "Povolit úpravy" v inteligentní značce GridView. Tím se vlastnost CommandField ShowEditButton nastaví na True, což vede k přidání tlačítka Upravit (a Aktualizovat a Zrušit tlačítka pro upravovaný řádek).

Konfigurace objektu GridView pro podporu úprav

Obrázek 10: Konfigurace ovládacího prvku GridView pro podporu úprav (kliknutím zobrazíte obrázek s plnou velikostí)

Přejděte na stránku v prohlížeči a klikněte na jedno z tlačítek upravit řádek. CategoryName a Description BoundField se vykreslují jako textová pole. BrochurePath TemplateField nemá EditItemTemplate, proto nadále zobrazuje svůj ItemTemplate jako odkaz na brožuru. Picture ImageField se vykresluje jako TextBox, jehož Text vlastnosti je přiřazena hodnota DataImageUrlField ImageField, v tomto případě CategoryID.

GridView nemá rozhraní pro úpravy pro BrochurePath

Obrázek 11: GridView nemá rozhraní pro BrochurePath úpravy (Kliknutím zobrazíte obrázek v plné velikosti)

PřizpůsobeníBrochurePathrozhraní pro úpravy

Potřebujeme vytvořit rozhraní pro úpravu pro TemplateField BrochurePath, které uživateli umožňuje:

  • Nechte brožuru kategorie as-is,
  • Aktualizujte brožuru kategorií tak, že nahrajete novou brožuru nebo
  • Úplně odeberte brožuru spojenou s kategorií (v případě, že kategorie již nemá přidruženou brožuru).

Potřebujeme také aktualizovat Picture rozhraní pro úpravy ImageFieldu, ale k tomu se dostaneme v kroku 7.

Z inteligentní značky GridView klikněte na odkaz Upravit šablony a v rozevíracím seznamu vyberte BrochurePath TemplateField s EditItemTemplate . Do této šablony přidejte ovládací prvek RadioButtonList Web a nastavte jeho vlastnost ID na BrochureOptions a jeho vlastnost AutoPostBack na True. V okně Vlastnosti klikněte na tři tečky v Items vlastnosti, což zobrazí ListItem Editor kolekcí. Přidejte následující tři možnosti s Value 1, 2 a 3:

  • Použití aktuální brožury
  • Odebrat aktuální brožuru
  • Nahrání nové brožury

Nastavte první ListItem s Selected vlastnost na True.

Přidat tři položky ListItems do RadioButtonList

Obrázek 12: Přidejte tři ListItem do seznamu RadioButton

Pod RadioButtonList přidejte ovládací prvek FileUpload s názvem BrochureUpload. Nastavte jeho vlastnost Visible na False.

Přidání ovládacího prvku RadioButtonList a FileUpload do EditItemTemplate

Obrázek 13: Přidání ovládacího prvku RadioButtonList a FileUpload do EditItemTemplate (kliknutím zobrazíte obrázek s plnou velikostí)

Tento RadioButtonList poskytuje uživateli tři možnosti. Myšlenka je, že ovládací prvek FileUpload se zobrazí pouze v případě, že je vybrána poslední možnost Nahrát novou brožuru. K tomu vytvořte obslužnou rutinu pro RadioButtonList s událostí SelectedIndexChanged a přidejte následující kód:

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

Vzhledem k tomu, že ovládací prvky RadioButtonList a FileUpload jsou v šabloně, musíme napsat část kódu pro programový přístup k těmto ovládacím prvkům. Odkaz na obslužnou rutinu SelectedIndexChanged události RadioButtonList je předán ve vstupním parametru sender. Abychom získali ovládací prvek FileUpload, musíme nejprve získat nadřazený ovládací prvek RadioButtonListu a poté použít metodu FindControl("controlID") odtud. Jakmile máme odkaz na ovládací prvky RadioButtonList a FileUpload, vlastnost ovládacího prvku FileUpload je nastavena na Visible pouze v případě, že hodnota vlastnosti RadioButtonList je rovna 3, což je True pro nahrát novou brožuru SelectedValue.

S tímto kódem chvíli otestujte rozhraní pro úpravy. Klikněte na tlačítko Upravit pro řádek. Na začátku by měla být vybrána možnost Použít aktuální brožuru. Změna vybraného indexu způsobí postback. Pokud je vybrána třetí možnost, zobrazí se ovládací prvek FileUpload, jinak je skrytý. Obrázek 14 znázorňuje rozhraní pro úpravy při prvním kliknutí na tlačítko Upravit; Obrázek 15 znázorňuje rozhraní po výběru možnosti Nahrát novou brožuru.

Na začátku je vybrána možnost Použít aktuální brožuru.

Obrázek 14: Na začátku je vybrána možnost Použít aktuální brožuru (kliknutím zobrazíte obrázek v plné velikosti).

Volba možnosti Nahrát novou brožuru Zobrazí ovládací prvek FileUpload

Obrázek 15: Volba možnosti Nahrát novou brožuru Zobrazí ovládací prvek FileUpload (Kliknutím zobrazíte obrázek v plné velikosti).

Uložení souboru brožury a aktualizaceBrochurePathsloupce

Když je kliknuto na tlačítko Aktualizovat v ovládacím prvku GridView, aktivuje se jeho RowUpdating událost. Příkaz aktualizace ObjectDataSource je vyvolán a poté se aktivuje událost GridView RowUpdated. Stejně jako u pracovního postupu odstraňování potřebujeme pro obě tyto události vytvořit obslužné rutiny událostí. V obslužné rutině RowUpdating události musíme určit, jakou akci provést na základě SelectedValue prvku BrochureOptions RadioButtonList.

  • SelectedValue Pokud je hodnota 1, chceme dál používat stejné BrochurePath nastavení. Proto musíme nastavit parametr ObjectDataSource na brochurePath existující BrochurePath hodnotu záznamu, který se aktualizuje. Parametr ObjectDataSource lze brochurePath nastavit pomocí e.NewValues["brochurePath"] = value.
  • Pokud je hodnota SelectedValue 2, chceme nastavit hodnotu záznamu BrochurePath na NULLhodnotu . Toho lze dosáhnout nastavením parametru ObjectDataSource brochurePath na Nothing, což má za následek použití databáze NULL v UPDATE příkazu. Pokud existuje soubor brožury, který se odebere, musíme existující soubor odstranit. Chceme to ale udělat jenom v případě, že se aktualizace dokončí bez vyvolání výjimky.
  • Pokud je hodnota SelectedValue 3, chceme zajistit, aby uživatel nahrál soubor PDF a pak ho uložil do systému souborů a aktualizoval hodnotu sloupce záznamu BrochurePath . Pokud je navíc existující soubor brožury, který se nahrazuje, musíme předchozí soubor odstranit. Chceme to ale udělat jenom v případě, že se aktualizace dokončí bez vyvolání výjimky.

Potřebné kroky k dokončení, když je hodnota RadioButtonList s SelectedValue 3, jsou prakticky identické s kroky, které provádí obslužná rutina události DetailsView ItemInserting. Tato obslužná rutina události se spustí při přidání nového záznamu kategorie z ovládacího prvku DetailsView, který jsme přidali v předchozím kurzu. Proto je na nás, abychom tuto funkcionalitu refaktorovali do samostatných metod. Konkrétně jsem přesunul společné funkce do dvou metod:

  • ProcessBrochureUpload(FileUpload, out bool) přijímá jako vstup instanci ovládacího prvku FileUpload a výstupní logickou hodnotu, která určuje, jestli má operace odstranění nebo úpravy pokračovat nebo jestli by měla být zrušena kvůli nějaké chybě ověření. Tato metoda vrátí cestu k uloženému souboru nebo null pokud nebyl uložen žádný soubor.
  • DeleteRememberedBrochurePath odstraní soubor určený cestou ve stránkové proměnné deletedCategorysPdfPath, pokud deletedCategorysPdfPath se nerovná null.

Kód pro tyto dvě metody následuje. Všimněte si podobnosti mezi ProcessBrochureUpload a obslužnou rutinou události DetailsView ItemInserting z předchozího kurzu. V tomto kurzu jsem aktualizoval obslužné rutiny událostí DetailsView tak, aby používaly tyto nové metody. Stáhněte si kód přidružený k tomuto kurzu, abyste viděli úpravy obslužných rutin událostí 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

Obslužné metody pro GridView RowUpdating a RowUpdated události používají metody ProcessBrochureUpload a DeleteRememberedBrochurePath, jak ukazuje následující kód:

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

Všimněte si, jak obslužná rutina RowUpdating události používá řadu podmíněných příkazů k provedení příslušné akce na základě hodnoty vlastnosti BrochureOptions RadioButtonList s SelectedValue.

S tímto kódem můžete upravit kategorii a nechat ji použít její aktuální brožuru, použít žádnou brožuru nebo nahrát novou. Klidně si to vyzkoušejte. Nastavte zarážky v obslužných rutinách událostí RowUpdating a RowUpdated, abyste získali představu o pracovním postupu.

Krok 7: Nahrání nového obrázku

Editační rozhraní Picture ImageField se vykreslí jako textové pole obsahující hodnotu z jeho DataImageUrlField vlastnosti. Během procesu úprav předává GridView modelu ObjectDataSource parametr, jehož název je hodnota vlastnosti ImageField s DataImageUrlField a jehož hodnota je vstup zadaný do textového pole v editačním rozhraní. Toto chování je vhodné, když je obrázek uložen jako soubor v systému souborů a DataImageUrlField obsahuje úplnou adresu URL obrázku. Za takových okolností zobrazí rozhraní pro úpravy adresu URL obrázku v textovém poli, které uživatel může změnit a uložit zpět do databáze. Toto výchozí rozhraní neumožňuje uživateli nahrát nový obrázek, ale umožňuje mu změnit adresu URL obrázku z aktuální hodnoty na jinou. Pro účely tohoto kurzu však výchozí rozhraní pro úpravy ImageField nestačí, protože Picture binární data jsou uložena přímo v databázi a DataImageUrlField vlastnost obsahuje pouze CategoryID.

Pokud chcete lépe porozumět tomu, co se stane v našem kurzu, když uživatel upraví řádek pomocí ImageFieldu, vezměte v úvahu následující příklad: uživatel upraví řádek s CategoryID hodnotou 10, což způsobí Picture vykreslení ImageField jako textové pole s hodnotou 10. Představte si, že uživatel změní hodnotu v tomto textovém poli na 50 a klikne na tlačítko Aktualizovat. Dojde k postbacku a GridView zpočátku vytvoří parametr CategoryID s hodnotou 50. Než však GridView odešle tento parametr (a CategoryName a Description parametry), přidá do hodnot z DataKeys kolekce. Proto přepíše CategoryID parametr základní hodnotou aktuálního řádku, což je CategoryID hodnota 10. Stručně řečeno, rozhraní pro úpravy ImageField nemá žádný vliv na pracovní postup úprav pro tento kurz, protože název vlastnosti ImageField s DataImageUrlField a hodnota mřížky DataKey jsou stejné.

I když ImageField usnadňuje zobrazení obrázku na základě databázových dat, nechceme do rozhraní pro úpravy zadat textové pole. Místo toho chceme nabídnout ovládací prvek FileUpload, který může koncový uživatel použít ke změně obrázku kategorie. BrochurePath Na rozdíl od hodnoty jsme se pro tyto kurzy rozhodli vyžadovat, aby každá kategorie měla obrázek. Proto nemusíme nechat uživatele indikovat, že neexistuje žádný přidružený obrázek, může buď nahrát nový obrázek, nebo nechat aktuální obrázek as-is.

Abychom přizpůsobili rozhraní pro úpravy ImageField, musíme ho převést na TemplateField. Z inteligentní značky GridView klikněte na odkaz Upravit sloupce, vyberte ImageField a převeďte toto pole na TemplateField.

Převod pole ImageField na templateField

Obrázek 16: Převod pole ImageField na templateField

Převod ImageField na TemplateField tímto způsobem vygeneruje TemplateField se dvěma šablonami. Jak ukazuje následující deklarativní syntaxe, ItemTemplate obsahuje ovládací prvek Image Web, jehož vlastnost ImageUrl je přiřazena pomocí syntaxe vazby dat na základě vlastností DataImageUrlField a DataImageUrlFormatString ImageFieldu. Obsahuje EditItemTemplate TextBox, jehož Text vlastnost je vázána na hodnotu určenou DataImageUrlField vlastností.

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

Potřebujeme aktualizovat EditItemTemplate na použití ovládacího prvku FileUpload. Klikněte na inteligentní značku GridView, vyberte odkaz Upravit šablony, a poté v rozevíracím seznamu vyberte Picture TemplateField EditItemTemplate. V šabloně byste měli vidět textové pole, které je třeba odstranit. Dále přetáhněte ovládací prvek FileUpload z panelu nástrojů do šablony a nastavte jeho ID na PictureUpload. Také přidejte text "Pro změnu obrázku kategorie zadejte nový obrázek". Pokud chcete zachovat stejný obrázek kategorie, nechte pole prázdné i v šabloně.

Přidání ovládacího prvku FileUpload do EditItemTemplate

Obrázek 17: Přidání ovládacího prvku FileUpload do EditItemTemplate (kliknutím zobrazíte obrázek s plnou velikostí)

Po přizpůsobení rozhraní pro úpravy si prohlédněte průběh v prohlížeči. Při prohlížení řádku v režimu pouze pro čtení se obrázek kategorie zobrazuje stejně jako předtím, ale kliknutím na tlačítko Upravit se sloupec obrázku změní na text s ovládacím prvkem pro nahrávání souboru (FileUpload).

Rozhraní pro úpravy obsahuje ovládací prvek FileUpload.

Obrázek 18: Rozhraní pro úpravy obsahuje ovládací prvek FileUpload (kliknutím zobrazíte obrázek v plné velikosti).

Vzpomeňte si, že ObjectDataSource je nakonfigurován pro volání metody třídy CategoriesBLL s UpdateCategory, která přijímá jako vstup binární data pro obrázek jako pole typu Byte. Pokud je toto pole Nothing, volá se alternativní přetížení UpdateCategory, které vydává SQL příkaz UPDATE, který neupravuje sloupec Picture, čímž ponechává aktuální obrázek kategorie nedotčený. Proto v obslužné rutině události GridView RowUpdating potřebujeme programově odkazovat na PictureUpload ovládací prvek FileUpload a určit, zda byl soubor odeslán. Pokud nebyl jeden nahrán, nechceme zadat hodnotu pro parametr picture. Na druhou stranu, pokud byl soubor nahraný v ovládacím PictureUpload prvku FileUpload, chceme zajistit, aby se jednalo o soubor JPG. Pokud ano, můžeme prostřednictvím parametru picture odeslat jeho binární obsah do ObjectDataSource.

Podobně jako u kódu použitého v kroku 6 existuje většina zde potřebného kódu v obslužné rutině události DetailsView ItemInserting . Proto jsem refaktoroval běžné funkce na novou metodu ValidPictureUploada aktualizoval obslužnou rutinu ItemInserting události tak, aby používala tuto metodu.

Na začátek obslužné rutiny události GridView přidejte následující kód RowUpdating. Je důležité, aby tento kód přišel před kód, který uloží soubor brožury, protože nechceme uložit brožuru do systému souborů webového serveru, pokud je odeslán neplatný soubor obrázku.

' 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

Metoda ValidPictureUpload(FileUpload) přebírá ovládací prvek FileUpload jako jediný vstupní parametr a zkontroluje příponu nahraného souboru, aby se zajistilo, že nahraný soubor je JPG. Volá se pouze v případě, že se nahraje soubor obrázku. Pokud se nenahraje žádný soubor, parametr obrázku není nastaven, a proto používá výchozí hodnotu Nothing. Pokud byl obrázek odeslán a ValidPictureUpload vrací True, picture parametr je přiřazen binární data nahraného obrázku; pokud metoda vrátí False, pracovní postup aktualizace je zrušen a obslužná rutina události ukončena.

Následuje kód ValidPictureUpload(FileUpload) metody, který byl refaktorován z obslužné rutiny události DetailsView ItemInserting:

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

Krok 8: Nahrazení původních obrázků kategorií soubory JPG

Vzpomeňte si, že původní osm kategorií obrázků jsou rastrové soubory zabalené v záhlaví OLE. Teď, když jsme přidali funkci pro úpravu existujícího obrázku záznamu, chvilku nahraďte tyto rastrové obrázky jpgy. Pokud chcete dál používat obrázky aktuální kategorie, můžete je převést na JPG provedením následujících kroků:

  1. Uložte rastrové obrázky na pevný disk. UpdatingAndDeleting.aspx Navštivte stránku v prohlížeči a pro každou z prvních osmi kategorií klikněte pravým tlačítkem myši na obrázek a vyberte, jestli chcete obrázek uložit.
  2. Otevřete obrázek v editoru obrázků podle svého výběru. Můžete například použít Microsoft Paint.
  3. Uložte rastrový obrázek jako obrázek JPG.
  4. Pomocí souboru JPG aktualizujte obrázek kategorie pomocí rozhraní pro úpravy.

Po úpravě kategorie a nahrání obrázku JPG se obrázek v prohlížeči nevykreslí, protože DisplayCategoryPicture.aspx stránka odstraní prvních 78 bajtů z obrázků prvních osmi kategorií. Tento problém opravte odebráním kódu, který provádí odstraňování záhlaví OLE. DisplayCategoryPicture.aspx``Page_Load Potom by obslužná rutina události měla mít pouze následující kód:

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

Poznámka:

Rozhraní pro vkládání a úpravu stránky UpdatingAndDeleting.aspx by si zasloužilo trochu více práce. CategoryName a Description pole BoundFields v DetailsView a GridView by měly být převedeny na pole TemplateFields. Vzhledem k tomu, že CategoryName nepovoluje NULL hodnoty, měl by být přidán RequiredFieldValidator. Description A TextBox by měl být pravděpodobně převeden na víceřádkový TextBox. Nechám tyto dokončovací práce jako cvičení pro vás.

Shrnutí

V tomto kurzu se podíváme na práci s binárními daty. V tomto kurzu a předchozích třech jsme viděli, jak lze binární data ukládat do systému souborů nebo přímo v databázi. Uživatel poskytuje systému binární data tak, že vybere soubor ze svého pevného disku a nahraje ho na webový server, kde ho můžete uložit do systému souborů nebo vložit do databáze. ASP.NET 2.0 obsahuje ovládací prvek FileUpload, který poskytuje takové rozhraní, že je stejně snadné jako přetáhnutí. Jak je ale uvedeno v kurzu Nahrávání souborů , ovládací prvek FileUpload je vhodný pouze pro relativně malé nahrávání souborů, ideálně nepřekračuje megabajt. Prozkoumali jsme také, jak přidružit nahraná data k podkladovému datovému modelu a jak upravit a odstranit binární data z existujících záznamů.

Naše další sada kurzů zkoumá různé techniky ukládání do mezipaměti. Ukládání do mezipaměti poskytuje způsob, jak zlepšit celkový výkon aplikace tím, že vezme výsledky z nákladných operací a uloží je do umístění, ke kterému se dostanete rychleji.

Šťastné programování!

O autorovi

Scott Mitchell, autor sedmi knih ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, trenér a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 během 24 hodin. Může být dosažitelný na mitchell@4GuysFromRolla.comadrese .

Zvláštní díky

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Vedoucí recenzentem pro tento návod byla Teresa Murphy. Chcete si projít nadcházející články MSDN? Pokud ano, napište mi zprávu na mitchell@4GuysFromRolla.com.