Aktualizace a odstranění stávajících binárních dat (C#)
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é Insert
metody , Update
a 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ší.
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 CategoryName
hodnoty , Description
a 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.
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 CategoryName
hodnoty , Description
a 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 null
př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.aspx
UpdatingAndDeleting.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
.
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í.
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é DeleteParameter
hodnotu . 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ě OldValuesParameterFormatString
deklarativní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
.
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 Categories
CategoryID
tabulkou 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.
Obrázek 6: Přidání testovací kategorie s brožurou a obrázkem (kliknutím zobrazíte obrázek v plné velikosti)
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ží.
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ě RowDeleting
CategoryID
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.
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ě OldValuesParameterFormatString
deklarativní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).
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
.
Obrázek 11: GridView nemá rozhraní pro úpravy (BrochurePath
kliknutím zobrazíte obrázek v plné velikosti)
PřizpůsobeníBrochurePath
rozhraní 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
.
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
.
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.
Obrázek 14: Zpočátku je vybraná možnost Použít aktuální brožuru (kliknutím zobrazíte obrázek v plné velikosti).
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 aktualizaceBrochurePath
sloupce
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 BrochureOptions
SelectedValue
RadioButtonList:
- Pokud je hodnota
SelectedValue
1, chceme dál používat stejnéBrochurePath
nastavení. Proto musíme nastavit parametr ObjectDataSource sbrochurePath
na existujícíBrochurePath
hodnotu aktualizovaného záznamu. Parametr ObjectDataSource sbrochurePath
lze nastavit pomocí .e.NewValues["brochurePath"] = value
- Pokud je hodnota
SelectedValue
2, chceme nastavit hodnotu záznamu naBrochurePath
NULL
hodnotu . Toho lze dosáhnout nastavením parametru ObjectDataSource sbrochurePath
na hodnotu , což vede kNothing
použití databázeNULL
vUPDATE
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 sBrochurePath
. 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 nebonull
pokud nebyl uložen žádný soubor.DeleteRememberedBrochurePath
odstraní soubor určený cestou v proměnnédeletedCategorysPdfPath
stránky, pokuddeletedCategorysPdfPath
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.
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ě.
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.
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, ValidPictureUpload
aby 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ů:
- 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. - Otevřete obrázek v editoru obrázků podle svého výběru. Můžete použít například Microsoft Malování.
- Uložte rastrový obrázek jako obrázek JPG.
- 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.