日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

57章:編輯和刪除現有的二進制數據

系統 2789 0


英文原版及代碼下載:
http://www.asp.net/learn/dataaccess/tutorial57cs.aspx?tabid=63


57章:編輯和刪除現有的二進制數據

導言:


在前面的3章里我們為處理二進制數據添加了很多的功能。我們首先在表Categories里添加BrochurePath列,并更新了體系結構。同樣,為了處理表Categorie里現有的Picture列,我們在數據訪問層和業務邏輯層里增加了相應的方法。同時我們創建一個頁面,在GridView控件里顯示二進制數據——包含一個指向說明小冊子的下載鏈接,并將每個類的圖片顯示在<img>元素里。同時我們添加一個DetailsView控件,供用戶添加新的類,并上傳其圖片和小冊子數據。


剩下的就是添加編輯和刪除功能,本章我們將通過GridView控件內建的編輯和刪除功能來實現。當編輯一個類時,我們允許用戶用任意指定的圖片將原來的換掉;也可以用新的小冊子將現有的替換掉,甚至不再包含小冊子文件。讓我們開始吧!

第1步:更新數據訪問層

雖然數據訪問層包含自動生成的Insert, Update和Delete方法,但它們都基于CategoriesTableAdapter的主查詢,因此并不包含Picture列。自然,Insert和Update
方法也不包含picture列的相應參數。就像56章做的那樣,我們需要為更新Categories表而創建新的TableAdapter方法。

右鍵點擊CategoriesTableAdapter的頂部,選擇“添加查詢”,打開TableAdapter查詢設置向導,我們首先選擇“使用SQL語句”,點Next,再選“UPDATE”,再點Next.

57章:編輯和刪除現有的二進制數據
圖1:選擇“UPDATE”選項


我們現在需要指定UPDATE SQL語句。向導自動創建一個基于TableAdapter主查詢的UPDATE語句(它更新CategoryName, Description和BrochurePath值)。更新該語句以包含Picture列,以及@Picture參數,像如下這樣:

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


最后,向導要求我們為新的TableAdapter方法命名,我們取為UpdateWithPicture,再點Finish。

57章:編輯和刪除現有的二進制數據
圖2:為新方法命名為UpdateWithPicture

第2步:添加新的業務邏輯方法


除了更新DAL外,我們需要更新BLL以包含更新、刪除類的方法。以下是表現層需要調用的方法:

為了刪除一個類,我們使用CategoriesTableAdapter的自動生成的Delete方法,在類CategoriesBLL里添加如下的方法:

[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;
}


本教程,為了更新一個類,我們將創建2個方法。一個方法接受picture值,并調用我們剛剛添加到CategoriesTableAdapter里的UpdateWithPicture方法。另一個方法只接受CategoryName, Description和BrochurePath值, 并調用CategoriesTableAdapter類里自動生成的Update語句。為什么要使用2種方法呢?某些情況下,用戶更新類時同時更新其圖片,這時就需要上傳一張新圖片。上傳圖片的數據將在UPDATE語句里用到;另一種情況,用戶只想更新類的name和description信息,因此我們需要使用2種更新方法。業務邏輯層會根據是否傳入picture值來判斷使用哪種方法。


為達該目的,我們要在CategoriesBLL類里添加2個方法,名字都是UpdateCategory,
第一個方法接受的參數包括3個string,1個byte數組和1個int;第二個方法接受的參數包括3個string和1個int。3個字符串參數代表類的name, description和brochure文件路徑,byte數組包含的是類的picture數據,int代表類記錄的CategoryID,我們注意到,當傳入的byte數組為null時,第一個方法將調用第二個方法。

[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;
}

第3步:拷貝功能


在56章里,我們創建了一個UploadInDetailsView.aspx頁面,在一個GridView控件列出所有的類,再通過一個DetailsView控件來添加新的類。在本教程,我們將擴展GridView控件以支持編輯和刪除功能。不過我們不再使用UploadInDetailsView.aspx頁面,讓我們在~/BinaryData文件夾里創建一個新頁面,UpdatingAndDeleting.aspx,將UploadInDetailsView.aspx頁面的聲明代碼復制并粘貼到頁面UpdatingAndDeleting.aspx.

打開UploadInDetailsView.aspx頁面,將其<asp:Content>元素里的聲明代碼復制下來,就像圖3那樣。接下來,打開UpdatingAndDeleting.aspx頁面,把代碼粘貼在<asp:Content>元素里。同樣的,將UploadInDetailsView.aspx頁面的后臺代碼拷貝到UpdatingAndDeleting.aspx。

57章:編輯和刪除現有的二進制數據
圖3:將UploadInDetailsView.aspx頁面的聲明代碼拷貝下來


完成后,登錄UpdatingAndDeleting.aspx頁面,你將會看到相同的輸出效果。感覺用起來和UploadInDetailsView.aspx頁面一樣。


第4步:添加ObjectDataSource和GridView的刪除功能

就像在教程16《概述插入、更新和刪除數據》里探討的一樣,只要GridView控件綁定的數據源支持“刪除”功能,我們就可以為GridView控件啟用刪除功能。不過,GridView控件綁定的ObjectDataSource(也就是CategoriesDataSource)目前并不支持刪除。


為支持刪除,在ObjectDataSource的智能標簽里點“配置數據源”,一直點到“定義數據方法”界面。雖然當前只指定了ObjectDataSource控件InsertMethod屬性和SelectMethod屬性,但向導自動地分別為UPDATE標簽和DELETE標簽指定UpdateCategory方法和DeleteCategory方法。為什么呢?因為我們在CategoriesBLL類里為上述2種方法使用了DataObjectMethodAttribute屬性,作用是分別使其成為默認的“更新”和“刪除”方法。


不過現在我們在UPDATE標簽的下拉列表里選“(None)”, 而 DELETE標簽里仍然為DeleteCategory方法。我們將在第6步添加更新功能。

57章:編輯和刪除現有的二進制數據

圖4:設置ObjectDataSource控件使用DeleteCategory方法

注意:
完成設置后,Visual Studio會問你是否“刷新列和主鍵”,選擇No,因為選擇Yes將會把我們自己定制的任何列覆蓋掉。

現在,ObjectDataSource控件將包含DeleteMethod屬性和對應的DeleteParameter參數
。我們記得在以前的教程提到過,當使用向導指定方法時,Visual Studio會自動的將ObjectDataSource控件的OldValuesParameterFormatString屬性設置為original_{0},這將導致更新和刪除時出現問題。為此,要么將清除該屬性,要么將其設置為默認的{0}值。對該屬性的更詳細討論見教程16《概述插入、更新和刪除數據》


完成后,ObjectDataSource控件的聲明代碼看起來應該像下面的一樣:

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


設置完ObjectDataSource后,就可以啟用GridView的刪除功能了,方法是點擊其智能標簽里的“刪除選項”。這將使GridView增加一個CommandField,其ShowDeleteButton屬性為true。

57章:編輯和刪除現有的二進制數據
圖5:啟用GridView控件的刪除功能


花幾分鐘測試刪除功能。由于表Products和表Categories之間有一個外鍵CategoryID,當你刪除現有的8個類中的任何一個時,你會得到一個外鍵約束沖突異常。為順利的實現測試,我們需要添加一個附帶圖片和說明小冊子的新類,如圖6所示,小冊子為Test.pdf,圖7為添加了測試類的GridView控件界面。

57章:編輯和刪除現有的二進制數據
圖6:添加一個附帶Brochure和Image文件的測試類

57章:編輯和刪除現有的二進制數據
圖7:添加測試類后,顯示在GridView控件里


在Visual Studio里刷新解決資源管理器,你會在文件夾~/Brochures里看到Test.pdf文件(見圖8)


下一步,點擊Test類的Delete鏈接,頁面回傳,引發CategoriesBLL的DeleteCategory 方法,該方法又調用DAL層的Delete方法,向數據庫發送適當的DELETE命令。最后數據重新綁定到GridView控件,Test類將不再顯示出來。


雖然已經成功地將Test類從Categories表刪除,但存儲在文件系統的對應小冊子仍舊存在,刷新解決資源管理器,你將發現Test.pdf依然放在~/Brochures文件夾里。

57章:編輯和刪除現有的二進制數據
圖8:Test.pdf文件并沒有從文件系統刪除


第5步:刪除殘存的Brochure文件


未將二進制數據存儲進數據庫時面臨的一個問題便是:當刪除一條數據庫記錄時,我們需要另外采取步驟來刪除該記錄對應的二進制數據文件。當執行delete命令時,會發生一些事前事件和事后事件(pre- and post-action events),我們需要創建對應的事件處理器。在Categories表的記錄被刪除之前,我們需要確定對應PDF文件的路徑,但在刪除記錄之前我們不會刪除其對應的PDF文件,以防發生異常或記錄最終未被刪除的情況。


從事件發生的時間先后順序來看,GridView控件的RowDeleting事件在調用ObjectDataSource控件的delete命令前發生;而RowDeleted事件在調用ObjectDataSource控件的delete命令之后再發生。創建這2個事件處理器,代碼如下:


// 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));
}
}
}


在RowDeleting事件處理器里,從GridView控件的DataKeys集合里獲取被刪記錄的CategoryID值,而在這里,我們通過e.Keys來訪問DataKeys集合。接著,調用類CategoriesBLL的GetCategoryByCategoryID(categoryID)方法來返回被刪記錄的信息,若返回的BrochurePath值不為NULL,那么將其賦值給頁面參數deletedCategorysPdfPath,再在RowDeleted事件處理器里刪除文件。
注意:
在RowDeleting事件處理器里,我們沒有返回被刪記錄的BrochurePath信息,而是將BrochurePath添加到GridView的DataKeyNames屬性,再通過訪問e.Keys來獲取該記錄的值。這樣做雖然稍微增大了GridView的視圖狀態,但減少了必要的代碼,也省了一步訪問數據庫。


調用ObjectDataSource控件的delete命令后,緊接著發生GridView控件的RowDeleted事件,如果刪除過程沒有異常且deletedCategorysPdfPath值不為空,那就將對應的PDF文件從文件系統刪除。我們注意到,代碼沒有刪除類的picture,那是因為picture數據是直接存儲在數據庫里的,當刪除記錄時就一起刪除了。


添加完上述2個事件處理器后,再次測試刪除。當刪除某個類時,其對應的PDF文件也刪除了。

下面我們深入研究添加更新功能以應對類的brochure和picture.第6步探討更新brochure信息的技術,第7章探討更新picture。


第6步:更新類的Brochure


就像在教程16《概述插入、更新和刪除數據》里探討的一樣,如果GridView的數據源控件支持編輯,那么我們就可以啟用GridView控件的編輯功能。當前,名為CategoriesDataSource的ObjectDataSource控件并不支持編輯,那讓我們添加吧。


點擊ObjectDataSource控件的“設置數據源”鏈接,一直點到“定義數據方法”界面。由于在CategoriesBLL里對重載的UpdateCategory方法使用了DataObjectMethodAttribute屬性,UPDATE標簽的下拉列表自動的選擇了該方法,它包含4個輸入參數(不包含Picture)。我們選擇另一個包含5個輸入參數的重載的UpdateCategory方法。

57章:編輯和刪除現有的二進制數據
圖9:設置ObjectDataSource控件使用包含Picture參數的UpdateCategory方法


ObjectDataSource控件現在包含了UpdateMethod屬性以及相應的UpdateParameters參數集。就像在第4步提到的一樣,當使用設置向導時,Visual Studio會將ObjectDataSource控件的OldValuesParameterFormatString屬性設置為original_{0},這導致調用update和delete方法時出現問題。因此,要么將該屬性清除,要么設該屬性為{0}。


完成后,ObjectDataSource控件的聲明代碼看起來應該和下面的差不多:

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

要啟用編輯功能,從GridView控件的智能標簽里選“編輯”。這將設置CommandField的ShowEditButton屬性為true,結果是為每行添加一個Edit按鈕(當記錄處于編輯狀態時,將呈現為Update和Cancel按鈕)

57章:編輯和刪除現有的二進制數據

圖10:啟用GridView控件的編輯功能


從瀏覽器查看該頁面,點某條記錄的Edit按鈕。CategoryName和Description列呈現為一個文本框。由于BrochurePath TemplateField沒有EditItemTemplate模板,所以它依舊呈現其ItemTemplate模板——一個指向brochure的鏈接。Picture列呈現為一個文本框,并且該Picture ImageField的Text屬性被指派為DataImageUrlField值,在這里,即CategoryID.

57章:編輯和刪除現有的二進制數據

圖11:BrochurePath列沒有編輯界面

定制BrochurePath編輯界面

我們可以為BrochurePath TemplateField創建一個編輯界面,我們可以選擇:

.維持原樣
.上傳新的brochure以作更新
.將brochure刪除(這樣一來,類就沒有對應的brochure了)

我們也應該更新Picture ImageField的編輯界面,不過我們將放在第7步來討論。


在GridView控件的智能標簽里選擇“編輯模板”,再從下拉列表里選BrochurePath TemplateField的EditItemTemplate模板。在模板里添加一個RadioButtonList Web控件,其ID為BrochureOptions;AutoPostBack屬性為true.再在屬性窗口里點Items屬性的橢圓型區域,進入ListItem Collection Editor界面,分別添加值為1,2,3的選項:

.Use current brochure
.Remove current brochure
.Upload new brochure

設第一個ListItem的Selected屬性為true.

57章:編輯和刪除現有的二進制數據

圖12:為RadioButtonList控件添加3個ListItems

在RadioButtonList控件下面,添加一個FileUpload控件,ID為BrochureUpload,設其Visible屬性為false。

57章:編輯和刪除現有的二進制數據
圖13:在EditItemTemplate模板里添加RadioButtonList和FileUpload控件


RadioButtonList控件為用戶提供了3個選擇,只有當選擇“Upload new brochure”時, FileUpload控件才會展現出來。為此,我們為RadioButtonList控件的SelectedIndexChanged事件創建事件處理器,如下:

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");
}


由于RadioButtonList控件和FileUpload控件同時出現在一個模板里,我們需要通過編程來訪問這2個控件。在SelectedIndexChanged事件處理器里,我們通過輸入參數sender來引用RadioButtonList控件。為了獲取FileUpload控件,我們需要使用RadioButtonList的父控件(parent control),并使用FindControl("controlID")方法。一旦我們同時獲取了RadioButtonList和FileUpload控件時,只要RadioButtonList控件的SelectedValue值等于3,即“Upload new brochure” ListItem的值時,將FileUpload控件的Visible屬性設置為true 。


添加完上述代碼后,花幾分鐘時間來測試編輯頁面。點擊某行的Edit按鈕,默認是選中“Use current brochure”項,改選另一項,頁面產生回傳,如果是選擇第3項,則FileUpload控件將會顯示出來,否則處于隱身狀態。圖14顯示點擊Edit按鈕的情形,而圖15則是選擇“Upload new brochure”時的情形。

57章:編輯和刪除現有的二進制數據

圖14:默認選擇“Use current brochure”項

圖15:選擇“Upload new brochure”時FileUpload控件顯示出來


保存Brochure文件并更新BrochurePath列


當點擊GridView控件的Update按鈕時,觸發RowUpdating事件,調用ObjectDataSource控件的update命令,然后觸發GridView控件的RowUpdated事件。跟deleting流程類似,我們需要創建這些事件的處理器。在RowUpdating事件處理器里,我們需要根據RadioButtonList的SelectedValue值來判斷下一步怎么做。

.如果SelectedValue值為1,我們將保持rochurePath不變。所以我們將ObjectDataSource控件的brochurePath參數設置為當前處于編輯狀態記錄的BrochurePath值,方法為e.NewValues["brochurePath"] = value.


.如果SelectedValue值為2,意味著將BrochurePath設為NULL。為此,我們需要將ObjectDataSource控件的brochurePath參數設為Nothing,結果就是在UPDATE命令里使用NULL。如果存在對應的brochure文件,我們必須將其刪除,前提是沒有拋出任何的異常。

.如果SelectedValue值為3,我們必須確保用戶已經上傳了一個PDF文件并將其保存在文件系統,然后更新記錄的BrochurePath值。我們要先將被替換的前一個文件刪除掉,當然前提是沒有引發異常。


在56章里,當在DetailsView控件里添加新記錄時,觸發DetailsView控件的ItemInserting事件。在本章,當RadioButtonList控件的SelectedValue為3時(即我們選擇Upload new brochure時),接下來要采取的步驟實際上與DetailsView控件的
ItemInserting事件處理器實現的功能相似。根據實現的功能,我劃分為2個方法:

.ProcessBrochureUpload(FileUpload, out bool):它以一個FileUpload控件實例為輸入參數,結果為一個布爾值(Boolean)。根據該布爾值判斷是否繼續更新或刪除操作,抑或取消操作。如果存在上傳文件該方法就返回其路徑,反之返回null。


.DeleteRememberedBrochurePath:如果頁面變量deletedCategorysPdfPath不為null,則刪除該參數指定的文件。


下面是上述2種方法的代碼。注意ProcessBrochureUpload方法和DetailsView控件的ItemInserting事件處理器有某些相似性,在本章,我們更新DetailsView控件的事件處理器以使用這些新方法。下載本章的代碼,查看我們對DetailsView控件的事件處理器所做的修改。


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));
}
}


在GridView控件的RowUpdating和RowUpdated事件處理器里使用上面2個方法,如下:

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();
}
}

注意RowUpdating事件處理器是如何根據SelectedValue值的不同而使用一系列的條件語句來實現相應的功能。


使用上面的代碼,我們就可以編輯一個類了,使用其當前的brochure,或不使用brochure,再或者使用一個新的brochure。在RowUpdating和RowUpdated事件處理器里設置斷點(breakpoints)吧,以便更好的理解處理流程。

第7步:上傳新圖片


Picture ImageField的編輯界面呈現為一個文本框,里面顯示的是DataImageUrlField 屬性的值。在編輯流程,GridView控件向ObjectDataSource傳入一個參數,參數名為ImageField的DataImageUrlField屬性;參數值為在編輯界面輸入文本框里的值。當圖片是存儲在文件系統,且DataImageUrlField屬性包含的是訪問該圖片的完整URL時,這樣做是恰當的。在這種情況下,在編輯界面里,文本框將會顯示圖片的URL。毫無疑問,默認的界面不允許用戶上傳新的圖片,但用戶卻可以修改圖片的URL值。不過,在本教程不會出現這種情況,因為Picture數據是直接存儲在數據庫的,且DataImageUrlField屬性被設為CategoryID值。


為了更好的理解在本教程里編輯某行的ImageField時將會發生上什么,我們做如下假設:用戶編輯一個CategoryID值為10行,Picture ImageField呈現為一個文本框,顯示10,假設用戶將其改為50后點Update按鈕,頁面回傳,GridView控件最初產生一個名為CategoryID,值為50的參數。在GridView傳遞此參數(連同參數CategoryName和參數Description一起)以前,對DataKeys集添加值。因此,將當前行的CategoryID值10,覆蓋掉。簡言之,ImageField的編輯界面沒有對本章教程的編輯流程產生任何影響,因為ImageField的DataImageUrlField屬性和DataKey值都是同一個值。


當圖片存儲在數據庫時,ImageField將其顯示出來也很容易。不過在編輯界面里我們不需要使用文本框,而提供一個FileUpload控件供最終用戶更改圖片時使用。與BrochurePath不同,我們不允許類的圖片為空——用戶要么提供新圖片要么使用當前的圖片。


為定制ImageField的編輯界面,我們需要將其轉化為一個TemplateField。在GridView控件的智能標簽里點擊“編輯列”,進入后選中ImageField,再點擊“Convert this field into a TemplateField”鏈接。

57章:編輯和刪除現有的二進制數據

圖16:將ImageField轉換為TemplateField

轉換后的TemplateField由2個模版構成。就像下面的聲明代碼顯示的那樣,ItemTemplate模版包含一個Image Web控件,其ImageUrl屬性由一個數據綁定語法指定,該數據綁定語法基于ImageField的DataImageUrlField和 DataImageUrlFormatString屬性。而EditItemTemplate模版則包含一個TextBox,其Text屬性綁定到DataImageUrlField屬性的值。


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


我們需要更新EditItemTemplate模版以包含一個FileUpload控件。從GridView控件的智能標簽點“編輯模版”,再在下拉列表選擇Picture TemplateField的EditItemTemplate模版。在模版里你會看見一個TextBox,將其刪除。從工具箱里拖一個FileUpload控件到頁面,設其ID為PictureUpload。同時在模版里添加如下的文本:“To change the category’s picture, specify a new picture. To keep the category’s picture the same, leave the field empty”。

57章:編輯和刪除現有的二進制數據
圖17:在EditItemTemplate模版里添加一個FileUpload控件


完成定制該編輯界面后,在瀏覽器里查看。在只讀模式里,類的圖片和以前沒什么兩樣,當點擊Edit按鈕時,picture列將呈現一段文本和一個FileUpload控件。

57章:編輯和刪除現有的二進制數據

圖18:編輯界面包含一個FileUpload控件


記得我們設置ObjectDataSource控件調用CategoriesBLL的UpdateCategory方法,
該方法的一個輸入參數為數組,用于處理圖片的數據。如果該數組為null值,則調用另一個重載的UpdateCategory方法,該重載的UpdateCategory方法的UPDATE SQL語句不會更改Picture列,因此類的圖片不會由任何變化。在GridView控件的RowUpdating事件處理器里,我們編程訪問名為PictureUpload的FileUpload控件,判斷是否上傳了文件。如果沒有 文件上傳 ,我們將不會為參數picture指定值;反之,如果上傳了文件,我們將確保其為JPG格式的文件,并通過參數picture將其傳給ObjectDataSource控件。


就像第6步里的代碼一樣,我們此時將要用到的絕大多數的代碼已經存在于DetailsView控件的ItemInserting事件處理器里了。現在我們創建一個新的方法ValidPictureUpload,并更新ItemInserting事件處理器以使用該方法。


在GridView控件的RowUpdating事件處理器的開頭部分添加如下的代碼,這很重要,因為我們不希望將一個不符合條件的上傳文件存儲在文件系統。

// 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;
}
}


ValidPictureUpload(FileUpload)方法只有一個FileUpload控件類型的輸入參數,通過檢查上傳文件的擴展符以確保上傳的文件為JPG格式。只有當上傳了文件時才會調用該方法;如果沒有 文件上傳 ,參數picture就只能使用其默認值—null。如果上傳了圖片,且ValidPictureUpload方法返回值true,將用圖片的二進制數據對參數picture賦值。如果ValidPictureUpload方法返回值false,則取消更新,并退出事件處理器。


ValidPictureUpload(FileUpload)方法的代碼如下:

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


第8步:將原始幾個類的圖片替換為JPG格式


回想起最開始的那8個類的圖片為位圖文件其包含一個OLE報頭。現在我們添加了新功能以編輯現有記錄的圖片,花幾分鐘將這些位圖文件替換為JPG文件。如果你想使當前類的圖片不變,你可以通過下面的布置將其轉換為JPG格式:

1.將這些位圖保存在硬盤。在瀏覽器里訪問UpdatingAndDeleting.aspx頁面,對這8個類的圖片,點右鍵,選則保存圖片。

2.在一個圖片編輯器(比如Microsoft Paint)軟件里打開圖片。

3.將圖片保存為JPG格式

4.在編輯界面里,用JPG圖片更新類的picture

完成更新并上傳JPG圖片之后,圖片不會呈現在瀏覽器里,原因是DisplayCategoryPicture.aspx將嘗試對最開始8個類的圖片剝離OLE報頭。怎樣修正呢?我們將剝離OLE報頭的代碼移除。這樣,DisplayCategoryPicture.aspx頁面的Page_Load事件處理器的代碼如下:

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);
}

注意:
UpdatingAndDeleting.aspx頁面的編輯和添加界面要稍微復雜一點。DetailsView和GridView控件里的CategoryName和Description BoundFields應當轉換成TemplateFields;另外由于CategoryName不能為NULL值,應對其添加一個RequiredFieldValidator控件。此外,Description應修改為允許換行的的文本框(multi-line TextBox),我將這些留給讀者作為練習。


總結:
本篇為處理二進制數據的完結篇,在本章以及前3章我們考察了如何將二進制數據存放在文件系統或直接存儲在數據庫里。用戶在硬盤里選擇一個文件并將其上傳到服務器,再存放在文件系統或數據庫。ASP.NET 2.0的FileUpload控件提供了上傳的界面。然而,就像在教程《上傳文件》里提到的那樣,FileUpload控件控件只適合于上傳小于1MB的文件。我們也探討了如何編輯和刪除當前記錄的二進制數據。

在接下來的一系列教程里,我們探討各種緩存技術。使用緩存可以提升應用程序的整體性能。


作者簡介
Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創始人,自1998年以來一直應用 微軟Web技術。Scott是個獨立的技術咨詢顧問,培訓師,作家,最近完成了將由Sams出版社出版的新作,24小時內精通ASP.NET 2.0。他的聯系電郵為 mitchell@4guysfromrolla.com ,也可以通過他的博客 http://ScottOnWriting.NET 與他聯系。

57章:編輯和刪除現有的二進制數據


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 永清县| 巧家县| 东兰县| 湘潭市| 衡东县| 阆中市| 新竹市| 开原市| 梨树县| 红安县| 焦作市| 密云县| 乌兰浩特市| 修武县| 高邮市| 囊谦县| 喀喇沁旗| 长泰县| 东丽区| 泰兴市| 获嘉县| 衡水市| 沭阳县| 沈丘县| 夹江县| 文山县| 沁源县| 尖扎县| 邢台市| 二连浩特市| 湘潭市| 佳木斯市| 邵武市| 梅河口市| 阿合奇县| 鄯善县| 雷州市| 浑源县| 安丘市| 清水河县| 广饶县|