Sdílet prostřednictvím


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

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 také umožňuje 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ě dost 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 aktualizovali architekturu. Přidali jsme také metody Data Access Layer (Vrstva přístupu k datům) a Business Logic Layer (Vrstva obchodní logiky), které pracují s existujícím Picture sloupcem tabulky Categories (Kategorie), který obsahuje binární obsah souboru obrázku. Vytvořili jsme webové stránky k prezentaci binárních dat v GridView odkaz ke stažení pro brožuru, 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 obrázek data.

Jediné, co zbývá implementovat, je možnost upravovat a odstraňovat existující kategorie, což provedeme v tomto kurzu pomocí integrovaných funkcí pro úpravy a odstraňování GridView. Při úpravách kategorie bude uživatel moct volitelně nahrát nový obrázek nebo nechat kategorii dál používat ten stávající. U brožury se můžou rozhodnout použít existující brožuru, nahrát novou brožuru nebo označit, že k ní již není přidružená žádná kategorie. Pojďme začít!

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

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

Otevřete sadu Typed DataSet a v Designer klikněte pravým tlačítkem na CategoriesTableAdapter záhlaví s a v místní nabídce zvolte Přidat dotaz, aby se spustil Průvodce konfigurací dotazu objektu TableAdapter. Tento průvodce začne tím, že se nás zeptá, jak by měl 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 v plné velikosti)

Teď musíme zadat UPDATE příkaz SQL. Průvodce automaticky navrhne UPDATE příkaz odpovídající hlavnímu dotazu objektu TableAdapter (který aktualizuje CategoryNamehodnoty , Descriptiona BrochurePath ). Změňte příkaz tak, aby Picture byl sloupec 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 vyzve k pojmenování nové metody TableAdapter. Zadejte UpdateWithPicture a klikněte na Dokončit.

Pojmenujte novou metodu TableAdapter UpdateWithPicture.

Obrázek 2: Pojmenujte novou metodu UpdateWithPicture 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. Toto jsou metody, které budou vyvolány z prezentační vrstvy.

K odstranění kategorie můžeme použít automaticky vygenerovanou Delete metodu CategoriesTableAdapter s. Do třídy CategoriesBLL přidejte následující metodu:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteCategory(int categoryID)
{
    int rowsAffected = Adapter.Delete(categoryID);
    // Return true if precisely one row was deleted, otherwise false
    return rowsAffected == 1;
}

Pro účely tohoto kurzu vytvoříme dvě metody aktualizace kategorie – jednu, která očekává data binárního obrázku a vyvolá metodu UpdateWithPicture , kterou jsme právě přidali do objektu CategoriesTableAdapter , a druhou, která přijímá pouze CategoryNamehodnoty , Descriptiona BrochurePath a používá CategoriesTableAdapter automaticky vygenerovaný Update příkaz třídy s. Zdůvodnění použití dvou metod spočívá v tom, že za určitých okolností může uživatel chtít aktualizovat obrázek kategorie spolu s ostatními poli. V takovém případě bude muset nahrát nový obrázek. V příkazu se pak dají použít binární data nahraného obrázku UPDATE . V jiných případech může uživatele zajímat pouze aktualizace, například, jméno a popis. Pokud UPDATE ale příkaz očekává binární data i pro Picture sloupec, pak bychom museli poskytnout i tyto informace. To by vyžadovalo další výlet do databáze, aby se vrátila data obrázku pro upravovaný záznam. Proto chceme dvě UPDATE metody. Vrstva obchodní logiky určí, kterou z nich použít, na základě toho, jestli se při aktualizaci kategorie poskytují data obrázků.

Pro usnadnění toho přidejte do CategoriesBLL třídy dvě metody, obě s názvem UpdateCategory. První z nich by měl jako vstupní parametry přijmout tři string s, byte pole a anint; druhý, pouze tři string s a .int Vstupní string parametry jsou pro název kategorie, popis a cestu k souboru brožury, byte pole je pro binární obsah obrázku kategorie a int určuje CategoryID záznam, který se má aktualizovat. Všimněte si, že první přetížení vyvolá druhé, pokud je nullpředávané byte pole :

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateCategory(string categoryName, string description, 
    string brochurePath, byte[] picture, int categoryID)
{
    // If no picture is specified, use other overload
    if (picture == null)
        return UpdateCategory(categoryName, description, brochurePath, categoryID);
    // Update picture, as well
    int rowsAffected = Adapter.UpdateWithPicture
        (categoryName, description, brochurePath, picture, categoryID);
    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}
[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateCategory(string categoryName, string description, 
    string brochurePath, int categoryID)
{
    int rowsAffected = Adapter.Update
        (categoryName, description, brochurePath, categoryID);
    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

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á uvádí všechny kategorie v GridView a poskytli DetailsView pro přidání nových kategorií do systému. V tomto kurzu rozšíříme zobrazení GridView tak, aby zahrnovalo podporu úprav a odstraňování. Místo toho, abyste pokračovali v práci z UploadInDetailsView.aspx, umístěte místo toho změny tohoto kurzu na UpdatingAndDeleting.aspx stránku ze stejné složky ~/BinaryData. Zkopírujte a vložte deklarativní kód a kód z do UploadInDetailsView.aspxUpdatingAndDeleting.aspx.

Začněte otevřením UploadInDetailsView.aspx stránky. Zkopírujte v elementu <asp:Content> veškerou deklarativní syntaxi, 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> elementu. Podobně zkopírujte kód z UploadInDetailsView.aspx třídy kódu na pozadí stránky do UpdatingAndDeleting.aspx.

Zkopírování deklarativního kódu z UploadInDetailsView.aspx

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

Po zkopírování deklarativního kódu a kódu přejděte na .UpdatingAndDeleting.aspx Měl by se zobrazit stejný výstup a mít stejné uživatelské prostředí jako UploadInDetailsView.aspx na stránce z předchozího kurzu.

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

Jak jsme si probrali v kurzu Přehled vkládání, aktualizace a odstraňování dat , GridView poskytuje integrované možnosti odstraňování a tyto funkce je možné povolit zaškrtnutím políčka, pokud podkladový zdroj dat mřížky podporuje odstranění. V současné době ObjectDataSource objektu GridView je vázán na (CategoriesDataSource) nepodporuje odstranění.

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

Prozatím nastavte rozevírací seznam AKTUALIZOVAT karty na (Žádné), ale rozevírací seznam delete tab s nechte nastavený na DeleteCategory. K tomuto průvodci se vrátíme v kroku 6 a přidáme podporu aktualizací.

Nakonfigurujte ObjectDataSource tak, aby používal metodu DeleteCategory.

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

Poznámka

Po dokončení průvodce se sada Visual Studio může zeptat, jestli chcete aktualizovat pole a klíče, čímž se znovu vygenerují pole webových ovládacích prvků dat. Zvolte Ne, protože pokud zvolíte Ano, přepíšete všechna možná vlastní nastavení polí.

ObjectDataSource teď bude obsahovat hodnotu pro svou DeleteMethod vlastnost a také DeleteParameterhodnotu . Vzpomeňte si, že při použití průvodce k určení metod sada Visual Studio nastaví vlastnost ObjectDataSource s OldValuesParameterFormatString na original_{0}, což způsobuje problémy s vyvoláním metody aktualizace a odstranění. Proto buď úplně vymažte tuto vlastnost, nebo ji resetujte na výchozí hodnotu {0}. Pokud potřebujete aktualizovat paměť u této vlastnosti ObjectDataSource, projděte si kurz Přehled vkládání, aktualizace a odstraňování dat .

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

<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 konfiguraci ObjectDataSource přidejte do objektu GridView možnosti odstraňování zaškrtnutím políčka Povolit odstranění z inteligentní značky GridView. Tím se do objektu GridView přidá commandfield, jehož ShowDeleteButton vlastnost je nastavená na true.

Povolení podpory pro odstranění v zobrazení GridView

Obrázek 5: Povolení podpory pro odstranění v zobrazení GridView (kliknutím zobrazíte obrázek v plné velikosti)

Chvíli si vyzkoušejte funkci odstranění. Mezi tabulkou s CategoryID a CategoriesCategoryIDtabulkou s existuje cizí klíčProducts, takže pokud se pokusíte odstranit některou z prvních osmi kategorií, zobrazí se výjimka porušení omezení cizího klíče. Pokud chcete tuto funkci otestovat, přidejte novou kategorii poskytující 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í testovací kategorie se zobrazí v zobrazení GridView.

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

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

Potom klikněte na odkaz Odstranit na řádku Test Category (Kategorie testu), což způsobí, že se stránka odpošle 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 vrátí do objektu GridView a značky se odešlou zpět klientovi s kategorií test už neexistuje.

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ík řešení a uvidíte, že Test.pdf ve ~/Brochures složce stále leží.

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

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

Krok 5: Odebrání souboru brožury odstraněné kategorie

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 aktivují 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 pro případ, že dojde k nějaké výjimce a kategorie se neodstraní.

Událost GridView s RowDeleting se aktivuje před vyvolání příkazu ObjectDataSource s delete, 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 
string deletedCategorysPdfPath = null;
protected void Categories_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    // Determine the PDF path for the category being deleted...
    int categoryID = Convert.ToInt32(e.Keys["CategoryID"]);
    CategoriesBLL categoryAPI = new CategoriesBLL();
    Northwind.CategoriesDataTable categories = 
        categoryAPI.GetCategoryByCategoryID(categoryID);
    Northwind.CategoriesRow category = categories[0];
    if (category.IsBrochurePathNull())
        deletedCategorysPdfPath = null;
    else
        deletedCategorysPdfPath = category.BrochurePath;
}
protected void Categories_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
    // Delete the brochure file if there were no problems deleting the record
    if (e.Exception == null)
    {
        // Is there a file to delete?
        if (deletedCategorysPdfPath != null)
        {
            System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath));
        }
    }
}

V obslužné rutině RowDeletingCategoryID události se z odstraněného řádku vezme z kolekce GridView s DataKeys , ke které je možné přistupovat v této obslužné rutině události prostřednictvím e.Keys kolekce. Dále se vyvolá třída sGetCategoryByCategoryID(categoryID), CategoriesBLL která vrátí informace o odstraněný záznam. Pokud vrácený CategoriesDataRow objekt nemá hodnotuNULL``BrochurePath , je uložen v proměnné deletedCategorysPdfPath stránky, aby mohl být soubor odstraněn v obslužné rutině RowDeleted události.

Poznámka

Místo načítání BrochurePath podrobností o Categories odstraněný záznam v RowDeleting obslužné rutině události jsme mohli alternativně přidat BrochurePath vlastnost GridView s DataKeyNames a přistupovat k hodnotě záznamu prostřednictvím e.Keys kolekce. Tím by se mírně zvětšila velikost stavu zobrazení objektu GridView, ale snížila by se velikost potřebného kódu a ušetřila by se cesta k databázi.

Po vyvolání základního příkazu delete ObjectDataSource se aktivuje obslužná rutina události GridView s RowDeleted . Pokud při odstraňování dat nedošlo k žádným výjimkám a existuje hodnota pro deletedCategorysPdfPath, odstraní se soubor PDF 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 kategorie s přidruženým k jejímu obrázku. Je to proto, že data obrázku jsou uložená přímo v databázi, takže odstraněním Categories řádku se odstraní 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é její přidružený SOUBOR PDF.

Aktualizace existujícího záznamu s přidruženými binárními daty přináší některé zajímavé výzvy. Zbývající část tohoto kurzu se bude zabývat přidáním možností aktualizace do brožury a obrázku. Krok 6 prozkoumá techniky aktualizace informací brožury, zatímco krok 7 se podívá na aktualizaci obrázku.

Krok 6: Aktualizace brožury Kategorie s

Jak je popsáno v kurzu Přehled vkládání, aktualizace a odstraňování dat , GridView nabízí integrovanou podporu úprav na úrovni řádků, kterou lze implementovat zaškrtnutím políčka, pokud je zdroj dat správně nakonfigurovaný. V současné době není objekt ObjectDataSource ještě nakonfigurovaný tak, CategoriesDataSource aby zahrnoval podporu aktualizací, takže ho přidáme.

V průvodci ObjectDataSource klikněte na odkaz Konfigurovat zdroj dat a pokračujte druhým krokem. Vzhledem k tomu, DataObjectMethodAttribute že se používá v CategoriesBLL, by měl být rozevírací seznam UPDATE automaticky naplněn přetížením UpdateCategory , které přijímá čtyři vstupní parametry (pro všechny sloupce kromě Picture). Změňte ho tak, aby se používalo přetížení s pěti parametry.

Nakonfigurujte ObjectDataSource tak, aby používal metodu UpdateCategory, která obsahuje parametr pro Picture.

Obrázek 9: Konfigurace objektu ObjectDataSource tak, aby používal metodu UpdateCategory , která obsahuje parametr pro Picture (kliknutím zobrazíte obrázek v plné velikosti)

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

Po dokončení průvodce a opravě 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 předdefinované funkce pro úpravy GridView, zaškrtněte možnost Povolit úpravy v inteligentní značce GridView. Tím se vlastnost CommandField s ShowEditButton nastaví na true, což způsobí přidání tlačítka Upravit (a tlačítka Aktualizovat a Zrušit pro upravovaný řádek).

Konfigurace objektu GridView pro podporu úprav

Obrázek 10: Konfigurace objektu GridView pro podporu úprav (kliknutím zobrazíte obrázek v plné velikosti)

Přejděte na stránku v prohlížeči a klikněte na jedno z tlačítek Pro úpravy řádku. Pole CategoryName a Description BoundField se vykreslí jako textová pole. TemplateField BrochurePath chybí EditItemTemplate, takže se stále zobrazuje ItemTemplate odkaz na brožuru. Pole Picture ImageField se vykreslí jako TextBox, jehož Text vlastnost je přiřazena hodnota ImageField s DataImageUrlField , v tomto případě CategoryID.

GridView nemá rozhraní pro úpravy pro BrožuruPath.

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

PřizpůsobeníBrochurePathrozhraní pro úpravy s

Pro TemplateField potřebujeme vytvořit rozhraní pro BrochurePath úpravy, které uživateli umožní:

  • Ponechte brožuru kategorie tak, jak je.
  • Aktualizujte brožuru kategorie tak, že nahrajete novou brožuru, nebo
  • Úplně odeberte brožuru kategorie (v případě, že tato kategorie už nemá přidruženou brožuru).

Musíme také aktualizovat Picture rozhraní pro úpravy ImageField, ale k tomu se dostaneme v kroku 7.

V inteligentní značce GridView klikněte na odkaz Upravit šablony a v rozevíracím seznamu vyberte BrochurePath TemplateField s EditItemTemplate . Přidejte do této šablony webový ovládací prvek RadioButtonList a nastavte jeho ID vlastnost na BrochureOptions a jeho AutoPostBack vlastnost na true. V okno Vlastnosti klikněte na tři tečky ve Items vlastnosti, čímž se zobrazí ListItem Editor kolekce. Přidejte následující tři možnosti s Value 1, 2 a 3 v uvedeném pořadí:

  • Použít aktuální brožuru
  • Odebrat aktuální brožuru
  • Nahrát novou brožuru

Nastavte první ListItem vlastnost s Selected na true.

Přidání tří ListItems do RadioButtonList

Obrázek 12: Přidání tří ListItem s do přepínače RadioButtonList

Pod RadioButtonList přidejte ovládací prvek FileUpload s názvem BrochureUpload. Nastavte jeho Visible vlastnost 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 v plné velikosti)

Tento RadioButtonList poskytuje tři možnosti pro uživatele. 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. Chcete-li toho dosáhnout, vytvořte obslužnou rutinu události pro událost RadioButtonList s SelectedIndexChanged a přidejte následující kód:

protected void BrochureOptions_SelectedIndexChanged(object sender, EventArgs e)
{
    // Get a reference to the RadioButtonList and its Parent
    RadioButtonList BrochureOptions = (RadioButtonList)sender;
    Control parent = BrochureOptions.Parent;
    // Now use FindControl("controlID") to get a reference of the 
    // FileUpload control
    FileUpload BrochureUpload = 
        (FileUpload)parent.FindControl("BrochureUpload");
    // Only show BrochureUpload if SelectedValue = "3"
    BrochureUpload.Visible = (BrochureOptions.SelectedValue == "3");
}

Vzhledem k tomu, že ovládací prvky RadioButtonList a FileUpload jsou v šabloně, musíme napsat trochu kódu, abychom k těmto ovládacím prvkům přistupovali programově. Obslužné SelectedIndexChanged rutině události je předán odkaz RadioButtonList ve vstupním parametru sender . Abychom získali ovládací prvek FileUpload, musíme získat nadřazený ovládací prvek RadioButtonList a použít metodu FindControl("controlID") odtud. Jakmile máme odkaz na oba RadioButtonList a FileUpload ovládací prvky FileUpload ovládací prvek s Visible je nastavena na pouze v true případě, že RadioButtonList s SelectedValue rovná 3, což je Value pro Nahrát novou brožuru ListItem.

S tímto kódem chvíli otestujte rozhraní pro úpravy. Klikněte na tlačítko Upravit u řádku. Zpočá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.

Zpočátku je možnost Použít aktuální brožuru vybraná.

Obrázek 14: Zpočátku je vybraná 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 SouborUpload.

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

Uložení souboru brožury a aktualizaceBrochurePathsloupce

Po kliknutí na tlačítko Aktualizovat GridView se jeho RowUpdating událost aktivuje. ObjectDataSource s update příkaz je vyvolán a pak se aktivuje událost GridView s RowUpdated . Stejně jako u pracovního postupu odstraňování potřebujeme vytvořit obslužné rutiny událostí pro obě tyto události. V obslužné rutině RowUpdating události musíme určit, jaká akce se má provést na základě parametru BrochureOptionsSelectedValue RadioButtonList:

  • Pokud je hodnota SelectedValue 1, chceme dál používat stejné BrochurePath nastavení. Proto musíme nastavit parametr ObjectDataSource s brochurePath na existující BrochurePath hodnotu aktualizovaného záznamu. Parametr ObjectDataSource s brochurePath lze nastavit pomocí .e.NewValues["brochurePath"] = value
  • Pokud je hodnota SelectedValue 2, chceme nastavit hodnotu záznamu na BrochurePathNULLhodnotu . Toho lze dosáhnout nastavením parametru ObjectDataSource s brochurePath na hodnotu , což vede k Nothingpoužití databáze NULL v UPDATE příkazu. Pokud už existuje soubor brožury, který se odebírá, musíme ho 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žit do systému souborů a aktualizovat hodnotu sloupce záznamu s BrochurePath . Kromě toho, pokud existuje existující soubor brožury, který se nahrazuje, musíme odstranit předchozí soubor. Chceme to ale udělat jenom v případě, že se aktualizace dokončí bez vyvolání výjimky.

Kroky, které je třeba provést, když je RadioButtonList s SelectedValue je 3, jsou prakticky stejné jako kroky používané obslužnou rutinou události DetailsView s 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 se nám sluší refaktorovat tuto funkci do samostatných metod. Konkrétně jsem přesunul běžné funkce do dvou metod:

  • ProcessBrochureUpload(FileUpload, out bool) přijímá jako vstup instanci ovládacího prvku FileUpload a výstupní logická hodnota, která určuje, zda má operace odstranění nebo úpravy pokračovat nebo zda 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 v proměnné deletedCategorysPdfPath stránky, pokud deletedCategorysPdfPath není null.

Kód pro tyto dvě metody následuje. Všimněte si podobnosti obslužné ProcessBrochureUpload rutiny události DetailsView s ItemInserting z předchozího kurzu. V tomto kurzu jsem aktualizoval(a) obslužné rutiny událostí DetailsView s 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 s.

private string ProcessBrochureUpload
    (FileUpload BrochureUpload, out bool CancelOperation)
{
    CancelOperation = false;    // by default, do not cancel operation
    if (BrochureUpload.HasFile)
    {
        // Make sure that a PDF has been uploaded
        if (string.Compare(System.IO.Path.GetExtension(BrochureUpload.FileName), 
            ".pdf", true) != 0)
        {
            UploadWarning.Text = 
                "Only PDF documents may be used for a category's brochure.";
            UploadWarning.Visible = true;
            CancelOperation = true;
            return null;
        }
        const string BrochureDirectory = "~/Brochures/";
        string brochurePath = BrochureDirectory + BrochureUpload.FileName;
        string fileNameWithoutExtension = 
            System.IO.Path.GetFileNameWithoutExtension(BrochureUpload.FileName);
        int iteration = 1;
        while (System.IO.File.Exists(Server.MapPath(brochurePath)))
        {
            brochurePath = string.Concat(BrochureDirectory, fileNameWithoutExtension, 
                "-", iteration, ".pdf");
            iteration++;
        }
        // Save the file to disk and set the value of the brochurePath parameter
        BrochureUpload.SaveAs(Server.MapPath(brochurePath));
        return brochurePath;
    }
    else
    {
        // No file uploaded
        return null;
    }
}
private void DeleteRememberedBrochurePath()
{
    // Is there a file to delete?
    if (deletedCategorysPdfPath != null)
    {
        System.IO.File.Delete(Server.MapPath(deletedCategorysPdfPath));
    }
}

Obslužné rutiny událostí a RowUpdated gridview RowUpdating používají ProcessBrochureUpload metody aDeleteRememberedBrochurePath, jak ukazuje následující kód:

protected void Categories_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    // Reference the RadioButtonList
    RadioButtonList BrochureOptions = 
        (RadioButtonList)Categories.Rows[e.RowIndex].FindControl("BrochureOptions");
    // Get BrochurePath information about the record being updated
    int categoryID = Convert.ToInt32(e.Keys["CategoryID"]);
    CategoriesBLL categoryAPI = new CategoriesBLL();
    Northwind.CategoriesDataTable categories = 
        categoryAPI.GetCategoryByCategoryID(categoryID);
    Northwind.CategoriesRow category = categories[0];
    if (BrochureOptions.SelectedValue == "1")
    {
        // Use current value for BrochurePath
        if (category.IsBrochurePathNull())
            e.NewValues["brochurePath"] = null;
        else
            e.NewValues["brochurePath"] = category.BrochurePath;
    }
    else if (BrochureOptions.SelectedValue == "2")
    {
        // Remove the current brochure (set it to NULL in the database)
        e.NewValues["brochurePath"] = null;
    }
    else if (BrochureOptions.SelectedValue == "3")
    {
        // Reference the BrochurePath FileUpload control
        FileUpload BrochureUpload = 
            (FileUpload)Categories.Rows[e.RowIndex].FindControl("BrochureUpload");
        // Process the BrochureUpload
        bool cancelOperation = false;
        e.NewValues["brochurePath"] = 
            ProcessBrochureUpload(BrochureUpload, out cancelOperation);
        e.Cancel = cancelOperation;
    }
    else
    {
        // Unknown value!
        throw new ApplicationException(
            string.Format("Invalid BrochureOptions value, {0}", 
                BrochureOptions.SelectedValue));
    }
    if (BrochureOptions.SelectedValue == "2" || 
        BrochureOptions.SelectedValue == "3")
    {
        // "Remember" that we need to delete the old PDF file
        if (category.IsBrochurePathNull())
            deletedCategorysPdfPath = null;
        else
            deletedCategorysPdfPath = category.BrochurePath;
    }
}
protected void Categories_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
    // If there were no problems and we updated the PDF file, 
    // then delete the existing one
    if (e.Exception == null)
    {
        DeleteRememberedBrochurePath();
    }
}

Všimněte si, že RowUpdating obslužná rutina události používá řadu podmíněných příkazů k provedení příslušné akce na BrochureOptions základě hodnoty vlastnosti 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. Jdi do toho a vyzkoušejte to. Nastavte zarážky v RowUpdating obslužných rutinách událostí a RowUpdated získejte představu o pracovním postupu.

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

Rozhraní Picture imageField s pro úpravy se vykresluje jako textové pole naplněné hodnotou z jeho DataImageUrlField vlastnosti. Během pracovního postupu úprav objektu GridView předá parametr ObjectDataSource s s hodnotou vlastnosti ImageField s DataImageUrlField a hodnotou parametru s hodnotu zadanou do textového pole v rozhraní pro úpravy. Toto chování je vhodné, pokud je obrázek uložen jako soubor v systému souborů a DataImageUrlField obsahuje úplnou adresu URL obrázku. Za takových okolností rozhraní pro úpravy zobrazí adresu URL obrázku v textovém poli, kterou uživatel může změnit a uložit zpět do databáze. Je pravda, že 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 ImageFieldu 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 pochopit, co se stane v našem kurzu, když uživatel upraví řádek s polem ImageField, podívejte se na následující příklad: uživatel upraví řádek s CategoryID hodnotou 10, což způsobí Picture , že imageField se vykresluje 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 zpětnému odeslání a GridView zpočátku vytvoří parametr s názvem CategoryID s hodnotou 50. Než však GridView odešle tento parametr (a CategoryName parametry a Description ), přidá hodnoty z DataKeys kolekce. Proto přepíše CategoryID parametr základní hodnotou aktuálního CategoryID řádku 10. Stručně řečeno, rozhraní pro úpravy ImageField s nemá žádný vliv na pracovní postup úprav pro tento kurz, protože názvy vlastnosti ImageField s DataImageUrlField a hodnoty s mřížky DataKey jsou stejné.

I když ImageField usnadňuje zobrazení obrázku založeného na datech databáze, nechceme v rozhraní pro úpravy poskytovat 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 uživateli umožnit, aby naznačoval, že neexistuje přidružený obrázek, který by uživatel mohl buď nahrát nový obrázek, nebo nechat aktuální obrázek tak, jak je.

Pokud chcete přizpůsobit 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 klikněte na odkaz Převést toto pole na TemplateField.

Převedení pole ImageField na templateField

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

Převod pole ImageField na TemplateField tímto způsobem vygeneruje Pole šablony se dvěma šablonami. Jak ukazuje následující deklarativní syntaxe, obsahuje ovládací prvek Image Web, ItemTemplate jehož ImageUrl vlastnost je přiřazena pomocí syntaxe vazby dat na základě ImageField s DataImageUrlField a DataImageUrlFormatString vlastností. 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>

Musíme aktualizovat EditItemTemplate ovládací prvek FileUpload. V inteligentní značce GridView klikněte na odkaz Upravit šablony a pak v rozevíracím seznamu vyberte Picture TemplateField s EditItemTemplate . V šabloně by se mělo zobrazit textové pole, které toto odebere. Dále přetáhněte ovládací prvek FileUpload z panelu nástrojů do šablony a nastavte jeho ID hodnotu na PictureUpload. Přidejte také text: Chcete-li změnit obrázek 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 v plné velikosti)

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 jen pro čtení se obrázek s kategorie zobrazuje tak, jak byl předtím, ale kliknutím na tlačítko Upravit se vykreslí sloupec obrázku jako text s ovládacím prvku SouborNačíst.

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í CategoriesBLL metody třídy s UpdateCategory , která přijímá jako vstup binární data pro obrázek jako byte pole. Pokud má null toto pole hodnotu, je volána alternativní UpdateCategory přetížení, která vydá UPDATE příkaz SQL, který neupravuje Picture sloupec, a tím ponechá aktuální obrázek kategorie beze změny. Proto v obslužné rutině události GridView s RowUpdating musíme programově odkazovat na PictureUpload ovládací prvek FileUpload a určit, zda byl soubor nahrán. Pokud nebyl nahrán, nechceme zadat hodnotu parametru picture . Na druhou stranu, pokud byl soubor nahrán do PictureUpload ovládacího prvku FileUpload, chceme zajistit, aby se jednalo o soubor JPG. Pokud ano, pak můžeme odeslat jeho binární obsah do ObjectDataSource prostřednictvím parametru picture .

Podobně jako u kódu použitého v kroku 6 už většina kódu, který je zde potřeba, existuje v obslužné rutině události DetailsView s ItemInserting . Proto jsem refaktoroval běžné funkce do nové metody a aktualizoval obslužnou rutinu ItemInserting události tak, ValidPictureUploadaby tuto metodu používala.

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

// Reference the PictureUpload FileUpload
FileUpload PictureUpload = 
    (FileUpload)Categories.Rows[e.RowIndex].FindControl("PictureUpload");
if (PictureUpload.HasFile)
{
    // Make sure the picture upload is valid
    if (ValidPictureUpload(PictureUpload))
    {
        e.NewValues["picture"] = PictureUpload.FileBytes;
    }
    else
    {
        // Invalid file upload, cancel update and exit event handler
        e.Cancel = true;
        return;
    }
}

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

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

private bool ValidPictureUpload(FileUpload PictureUpload)
{
    // Make sure that a JPG has been uploaded
    if (string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
            ".jpg", true) != 0 &&
        string.Compare(System.IO.Path.GetExtension(PictureUpload.FileName), 
            ".jpeg", true) != 0)
    {
        UploadWarning.Text = 
            "Only JPG documents may be used for a category's picture.";
        UploadWarning.Visible = true;
        return false;
    }
    else
    {
        return true;
    }
}

Krok 8: Nahrazení obrázků původních 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 možnost upravit existující obrázek záznamu, chvíli nahrazujte tyto rastrové obrázky soubory JPG. Pokud chcete dál používat obrázky aktuální kategorie, můžete je převést na soubory JPG provedením následujících kroků:

  1. Uložte rastrové obrázky na pevný disk. Přejděte na UpdatingAndDeleting.aspx 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 zvolte, jestli chcete obrázek uložit.
  2. Otevřete obrázek v editoru obrázků podle svého výběru. Můžete použít například Microsoft Malování.
  3. Uložte rastrový obrázek jako obrázek JPG.
  4. Aktualizujte obrázek kategorie pomocí rozhraní pro úpravy pomocí souboru JPG.

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

protected void Page_Load(object sender, EventArgs e)
{
    int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]);
    // Get information about the specified category
    CategoriesBLL categoryAPI = new CategoriesBLL();
    Northwind.CategoriesDataTable categories = _
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID);
    Northwind.CategoriesRow category = categories[0];
    // For new categories, images are JPGs...
    
    // Output HTTP headers providing information about the binary data
    Response.ContentType = "image/jpeg";
    // Output the binary data
    Response.BinaryWrite(category.Picture);
}

Poznámka

Rozhraní UpdatingAndDeleting.aspx pro vkládání a úpravy stránek by mohla znamenat trochu více práce. Description A CategoryName BoundFields v DetailsView a GridView by měly být převedeny na TemplateFields. Vzhledem k tomu CategoryName , že nepovoluje NULL hodnoty, měl by být přidán RequiredFieldValidator. Description TextBox by se měl pravděpodobně převést na víceřádkové textové pole. Tyhle dokončovací doteky nechávám jako cvičení pro vás.

Souhrn

Tento kurz doplňuje náš pohled na práci s binárními daty. V tomto kurzu a předchozích třech jsme viděli, jak mohou být binární data uložena v systému souborů nebo přímo v databázi. Uživatel poskytne systému binární data tak, že vybere soubor z pevného disku a nahraje ho na webový server, kde je lze uložit v systému souborů nebo vložit do databáze. ASP.NET 2.0 obsahuje ovládací prvek FileUpload, který poskytuje takové rozhraní tak snadné, jako je přetažení. Jak je však uvedeno v kurzu Nahrávání souborů , ovládací prvek FileUpload je vhodný pouze pro relativně malé nahrávání souborů, v ideálním případě 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ů se zabývá různými technikami 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 přebírá výsledky z nákladných operací a ukládá je do umístění, ke kterému je možné rychleji přistupovat.

Šťastné programování!

O autorovi

Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho zastihnout na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na adrese http://ScottOnWriting.NET.

Zvláštní poděkování

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavní revidující pro tento kurz byla Teresa Murphyová. Chtěli byste si projít své nadcházející články na webu MSDN? Pokud ano, dejte mi řádek na mitchell@4GuysFromRolla.com.