程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> ASP.NET基礎 >> 在ASP.NET 2.0中操作數據之四十九:為GridView控件添加RadioButton

在ASP.NET 2.0中操作數據之四十九:為GridView控件添加RadioButton

編輯:ASP.NET基礎

導言:

  GridView控件提供了大量的內置功能。它包含了一系列的域(field)來顯示諸如text、images、hyperlinks和buttons。另外它支持模板(template)用於用戶自定義界面。我們可以構建這樣一個GridView控件,用戶僅需要點擊控件裡的一個按鈕,每一條記錄行都可以選擇、編輯、刪除。除了控件本身內置的功能外,在某些情況下,我們添加一些額外的、控件沒有內置的功能。在本章及接下來的2篇教程裡我們將探討如何優化GridView,以支持額外的功能。

  本篇及接下來的教程將主要探討優化行選擇程序(row-selection process),就像在教程《使用 GridView和DetailView實現的主/從報表》裡考察的一樣,我們在GridView控件裡添加一個包含選擇按鈕的命令域(CommandField),點擊該按鈕後產生回傳(postback),所選行的index值傳給GridView控件的SelectedIndex屬性。在那篇教程裡我們看到了如何使用該功能顯示所選行的詳細信息。

  除了Select button,我們經常在用戶界面包含radio button和checkbox用於選擇記錄。在某些情況下我們可以對GridView擴充,在每條記錄裡用radio button或checkbox替換掉Select button。比如,我們只希望選擇GridView記錄中的一條時,用radio button比用Select button好;再比如,當用戶要選擇多條記錄時——就像在郵箱裡同時刪除幾份郵件一樣,用checkbox是最好的。本教程先考察為GridView添加radio buttons,再考察添加checkboxes。

第一步:創建優化GridView的Web頁面

  在開始之前讓我們在網站項目裡創建一個本節及後面2節要用到的ASP.NET頁面。新建一個名為EnhancedGridView的文件夾,然後,添加如下所示的頁面,確保使用Site.master母版。

Default.aspx
RadioButtonField.aspx
CheckBoxField.aspx
InsertThroughFooter.aspx

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916445999.gif
圖1:添加相關頁面

  像其它文件夾一樣,Default.aspx頁面將顯示本節的所有教程。記得用戶控件SectionLevelTutorialListing.ascx提供該功能,從解決方案管理器裡將其拖到Default.aspx頁面上。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916445990.gif
圖2:添加用戶控件SectionLevelTutorialListing.ascx

  最後,將這4篇教程添加到Web.sitemap文件裡,特別的,加在“Using the SqlDataSource Control” <siteMapNode>後:

<siteMapNode 
 title="Enhancing the GridView" 
 url="~/EnhancedGridView/Default.aspx" 
 description="Augment the user experience of the GridView control.">
 <siteMapNode 
 url="~/EnhancedGridView/RadioButtonField.aspx" 
 title="Selection via a Radio Button Column" 
 description="Explore how to add a column of radio buttons in the GridView." />
 <siteMapNode 
 url="~/EnhancedGridView/CheckBoxField.aspx" 
 title="Selection via a Checkbox Column" 
 description="Select multiple records in the GridView by using a column of 
  checkboxes." />
 <siteMapNode 
 url="~/EnhancedGridView/InsertThroughFooter.aspx" 
 title="Add New Records through the Footer" 
 description="Learn how to allow users to add new records through the 
  GridView's footer." />
</siteMapNode>

完成後,花幾分鐘在浏覽器查看該系列教程,如圖所示:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916445954.gif
圖3:Site Map裡完整地列出了本系列教程

第2步:在GridView控件裡顯示供應商

  讓我們創建一個GridView控件,用於顯示來自美國的供應商列表,同時每行記錄包含一個radio button。當點擊radio button後,用戶將查看到供應商提供的產品。在開始具體研究如何實現以前,我們先創建一個顯示供應商的GridView。

  在文件夾EnhancedGridView裡打開adioButtonField.aspx頁面,進入設計模式,從工具箱拖一個GridView到頁面。設其ID為Suppliers,在智能標簽裡選“創建新數據源”,特別的,我們選用ObjectDataSource,命名為SuppliersDataSource,然後選用SuppliersBLL 。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450095.gif
圖4:創建一個名為SuppliersDataSource的ObjectDataSource

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450077.gif
圖5:設置該ObjectDataSource使用SuppliersBLL類

因為我們只想列出來自美國的供應商,在SELECT選項卡的下拉列表裡選擇 GetSuppliersByCountry(country)方法。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450023.gif
圖6:設置該ObjectDataSource使用SuppliersBLL類(原文如此)

在UPDATE選項卡選擇“(None)”,點下一步

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450126.gif
圖7:設置該ObjectDataSource使用SuppliersBLL類(原文如此)

  因為GetSuppliersByCountry(country)方法需要接受一個參數,向導提示我們設置參數源,在這裡我們指定一個“硬編碼”值(就本例而言,我們指定USA),在數據源下拉列表裡選“None”,在指定值文本框輸入“USA”。點“完成”結束向導設置。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450181.gif
圖8:為參數country使用默認值“USA”

  只保留GridView裡的CompanyName, City和Country三列(BoundFields),其余的全部刪除。同時將CompanyName列的HeaderText屬性改為“Supplier”。設置完以後, GridView和ObjectDataSource控件的聲明代碼看起來和下面的差不多:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
 DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
 EnableViewState="False">
 <Columns>
 <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
  SortExpression="CompanyName" />
 <asp:BoundField DataField="City" HeaderText="City" 
  SortExpression="City" />
 <asp:BoundField DataField="Country" HeaderText="Country" 
  SortExpression="Country" />
 </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server" 
 OldValuesParameterFormatString="original_{0}"
 SelectMethod="GetSuppliersByCountry" TypeName="SuppliersBLL">
 <SelectParameters>
 <asp:Parameter DefaultValue="USA" Name="country" Type="String" />
 </SelectParameters>
</asp:ObjectDataSource>

  在本篇教程,當點擊某個供應商時,將在本業或另一頁顯示該供應商提供的產品。為達到該目的,我們在頁面添加2個Button Web控件。ID分別為ListProducts和SendToProducts,當點擊ListProducts按鈕時,發生回傳(postback),接著將在本頁面顯示該供應商的產品,當點擊SendToProducts按鈕時,將會鏈接到另一個頁面,顯示該供應商的產品。
圖9顯示了GridView控件和添加的兩個Button Web控件。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450217.gif
圖9:顯示供應商的 Name, City和Country信息

第3步:添加Radio Buttons列

  至此,GridView裡包含company name, city和country三列,但還缺少radio buttons列。不幸的是GridView控件並不包含內置的RadioButtonField,因此只有我們自己手動添加。我們可以添加一個模板(TemplateField)並在其ItemTemplate模板裡顯示一個radio button。這樣的話就為GridView控件的每一行記錄添加了一個radio button。

  我們首先可能會想到直接在TemplateField的ItemTemplate模版裡添加一個RadioButton Web控件。不錯,這樣將為每一行添加radio button,但是這些radio button不能聚合,因此不能形成互斥關系。造成的後果是,最終用戶可以在GridView控件裡同時選定多個radio button按鈕。

  雖然這樣做不能到達我們期望的要求,不過還是值得我們花時間來考察一下為什麼這些radio button不能聚合。首先,為GridView添加一個TemplateField,放置在最左邊,然後智能標簽裡選“編輯模板”,進入TemplateField的ItemTemplate 模板,從工具箱拖一個Radio Button控件到模板(見圖10),設置其ID為RowSelector , GroupName屬性為SuppliersGroup。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450264.gif
圖10:在ItemTemplate模板添加一個RadioButton控件

完成設置後,GridView的代碼看起來應和下面的差不多:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
 DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
 EnableViewState="False">
 <Columns>
 <asp:TemplateField>
  <ItemTemplate>
  <asp:RadioButton ID="RowSelector" runat="server" 
   GroupName="SuppliersGroup" />
  </ItemTemplate>
 </asp:TemplateField>
 <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
  SortExpression="CompanyName" />
 <asp:BoundField DataField="City" HeaderText="City" 
  SortExpression="City" />
 <asp:BoundField DataField="Country" HeaderText="Country" 
  SortExpression="Country" />
 </Columns>
</asp:GridView>

  RadioButton的GroupName屬性的作用在於:具有相同GroupName值的RadioButton控件被認為是一個組,在一個組裡面只有一個控件可以被選擇(即具有互斥性)。GroupName屬性為radio button的名稱特征(nameattribute)指定值,浏覽器檢查radio button的名稱特征,再對其分組。

  在浏覽器裡查看頁面,選擇所有行,可以看出這些radio button並沒有聚合(也就是不具有互斥性),如圖11所示:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450318.gif
圖11:GridView的Radio Buttons沒有聚合。

  不能聚合的原因在於:盡管將他們的GroupName屬性設置為相同的,但提交的名稱屬性是不同的。在浏覽器裡點查看/源代碼,檢查這些radio button的代碼:

<input id="ctl00_MainContent_Suppliers_ctl02_RowSelector" 
 name="ctl00$MainContent$Suppliers$ctl02$SuppliersGroup" 
 type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl03_RowSelector" 
 name="ctl00$MainContent$Suppliers$ctl03$SuppliersGroup" 
 type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl04_RowSelector" 
 name="ctl00$MainContent$Suppliers$ctl04$SuppliersGroup" 
 type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl05_RowSelector" 
 name="ctl00$MainContent$Suppliers$ctl05$SuppliersGroup" 
 type="radio" value="RowSelector" />

  我們注意到,這裡的name和id值和在屬性窗口指定的准確值(exact values)相比,在開頭多了一些其它ID值(比如id="ctl00_MainContent_Suppliers_ctl02_RowSelector" 和ID="RowSelector"相比),這些多出來的IDs值來自於這些 radio buttons的父級控件(parent controls)——GridViewRow、GridView、Content control以及Web Form。加上這些IDs的目的是使GridView控件裡的每個rendered Web control(具體到本例就是這些radio button)具有唯一的id值和name值。

  這樣做的原因在於:在客戶端,便於浏覽器區分每個rendered control(比如本章的radio button);在網絡服務器端,便於服務器區分當頁面回傳時發生了什麼事件或改變。比如,無論何時,當一個 RadioButton的選中狀態(checked state)發生改變時,我們希望運行某些服務器端代碼。為此,我們可以將RadioButton的AutoPostBack屬性設置為true,同時為CheckChanged事件創建一個事件處理器。如果每個radio buttons的name和id值相同的話,當發生頁面回轉時,我們不能確定到底點擊了哪個RadioButton。

  這樣做的缺點在於,我們不能用RadioButton Web 控件在GridView裡創建一個radio button列。因此,我們必須在GridView row裡添加適當的代碼。

  注意:和RadioButton Web控件一樣,當把radio button HTML控件添加到模板時,它也會包含唯一的名稱特征。如果你不熟悉HTML控件,沒關系,因為很少使用它,尤其在ASP.NET 2.0裡。如果有興趣了解更多,見 K. Scott Allen的博客裡的文章Web Controls and HTML Controls.

用Literal控件注入Radio Button代碼

  為了在GridView控件裡對radio buttons進行聚合,我們要在ItemTemplate模板裡手動注入radio button代碼。每個radio button具有相同的name特性,但id特性必須是唯一的(因為我們可能需要通過客戶端腳本訪問某個radio button)。因為當用戶選擇了一個radio button,頁面回傳後,浏覽器將返回該按鈕的一個值,所以每個radio button要具備一個唯一值特性(unique value attribute)。最後,當選擇一個radio button後,我們應確保為該按鈕添加checked屬性。另外,用戶做了選擇並發生回傳後,radio button將回到默認狀態(可任意指定)。

  可以有2種方法在模板裡注入代碼。其中一種是在代碼裡調用定義在後台代碼類(code-behind class)裡的方法,並使用格式化的形式。這個方法我們在教程《在GridView控件中使用TemplateField》裡論述過。在本例,代碼看起來像這個樣子:

<input type="radio" id='<%# GetUniqueRadioButtonID(...) %>' 
 name='SuppliersGroup' value='<%# GetRadioButtonValue(...) %>' ... />

  其中,GetUniqueRadioButton和GetRadioButtonValue是定義在後台代碼類裡的方法,其作用是返回特定的id和value值。用這種可以對radio button的id屬性和 value屬性賦值,但不能對checked屬性賦值。因為只有當數據第一次綁定到該GridView控件時,數據綁定語法才能成功執行。所以只有當啟用GridView的試圖狀態,並且是第一次登錄頁面(或者明確的讓GridView重新綁定數據源)時這種格式化的方法才能奏效。所以,當頁面發生回傳時,對checked屬性賦值的這個功能是失效的。這個問題有點超出了本教程的范圍,所以在這裡我將它擱置一邊,然而我仍然鼓勵你用上面的這個方法。這個練習將使你更深入的理解GridView以及數據綁定的生命周期。

  第2種,也是本教程要用的方法是在模板裡添加一個Literal控件。在GridView的RowCreated或RowDataBound事件處理器裡,我們可以通過編程來訪問Literal控件,並設置其Text屬性。

  在TemplateField的ItemTemplate模板裡,移除RadioButton控件,換成Literal控件,設其ID為RadioButtonMarkup。

 https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450642.gif
圖12:在ItemTemplate模板裡添加一個Literal控件

  然後,為GridView的RowCreated事件創建事件處理器。RowCreated事件是這樣的,不管數據是不是重新綁定到GridView,只要在GridView裡新增一行記錄就將引發RowCreated事件。那意味著,當發生回傳事件時,哪怕數據來自視圖狀態,也會引發RowCreated事件。我們使用RowCreated事件而不使用RowDataBound事件的原因在於,只有當數據明確的綁定到數據Web控件時才會引發RowDataBound事件.


  在RowCreated事件處理器裡,我們處理的是某一行記錄。對每一行記錄,我們通過編程引用Literal控件RadioButtonMarkup,然後在其Text屬性裡聲明代碼。比如下面的代碼,我們創建一個radio button ,設置其name屬性為SuppliersGroup,id屬性為RowSelectorX,其中X代表 GridView row的index值,將value屬性也設置為GridView row的index值。

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
 if (e.Row.RowType == DataControlRowType.DataRow)
 {
  // Grab a reference to the Literal control
  Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
  // Output the markup except for the "checked" attribute
  output.Text = string.Format(
   @"<input type="radio" name="SuppliersGroup" " +
   @"id="RowSelector{0}" value="{0}" />", e.Row.RowIndex);
 }
}

  當選擇GridView控件的某條記錄時,我們關心的是該供應商的SupplierID值。我們首先會想到讓radio button的value屬性返回該SupplierID值(而不是該條記錄的index值)。然而這樣盲目地獲取並傳遞一個SupplierID值是很危險的。以我們的GridView控件為例,它列出了所有的美國供應商,如果我們直接通過radio button來傳遞SupplierID,我們無法阻止一個帶有惡意的用戶對回傳過來的SupplierID造假。通過將value屬性設置為某條記錄的index值,當發生頁面回傳時,從DataKeys集合裡獲取該供應商的SupplierID值。這樣的話,我們就能確保用戶只能使用GridView裡某個供應商的對應的SupplierID值。

  添加完事件處理器代碼後,花幾分鐘在浏覽器裡測試該頁面,首先確保每次只能選擇一個radio button。然而,當選擇一個radio button並點擊下面的按鈕,在頁面發生回傳後,所有的radio button都回到最初的狀態(意即,發生回傳後,選中的radio button又恢復未選狀態)。怎樣解決這個問題呢?我們在RowCreated事件處理器裡添加代碼,先確定發生頁面回傳後,選中的那個radio button的index值,然後添加checked="checked"屬性。

  當發生頁面回傳後,浏覽器返回選中的radio button的name和value值.我們可以通過編程來獲取值,比如:Request.Form["name"]。Request.Form屬性用一個NameValueCollection來表示form變量。在這裡,form變量就是發生回轉時,浏覽器返回的那些names和values值。 因為GridView控件裡的radio buttons的name屬性是SuppliersGroup,當頁面發生回轉時,浏覽器向網絡服務器傳回“SuppliersGroup=valueOfSelectedRadioButton”(連同其它form fields一起傳回)。我們可以用Request.Form屬性訪問這些信息:Request.Form["SuppliersGroup"]

  我們不僅需要在RowCreated事件處理器中確定所選radio button的index值,在Click事件處理器裡同樣需要。讓我們在後台代碼類裡創建SuppliersSelectedIndex。如果沒有radio button被選定則返回-1,如果有radio button被選定則返回它的index值。如下:

private int SuppliersSelectedIndex
{
 get
 {
  if (string.IsNullOrEmpty(Request.Form["SuppliersGroup"]))
   return -1;
  else
   return Convert.ToInt32(Request.Form["SuppliersGroup"]);
 }
}

  當SuppliersSelectedIndex的值與e.Row.RowIndex的值相同時,我們應在RowCreated事件處理器裡添加checked="checked"代碼。修改如下:

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
 if (e.Row.RowType == DataControlRowType.DataRow)
 {
  // Grab a reference to the Literal control
  Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
  // Output the markup except for the "checked" attribute
  output.Text = string.Format(
   @"<input type="radio" name="SuppliersGroup" " +
   @"id="RowSelector{0}" value="{0}"", e.Row.RowIndex);
  // See if we need to add the "checked" attribute
  if (SuppliersSelectedIndex == e.Row.RowIndex)
   output.Text += @" checked="checked"";
  // Add the closing tag
  output.Text += " />";
 }
}

  經過上述修改後,選中的radio button在頁面回傳後仍然處於選中狀態。現在我們可以指定某個radio button處於選中狀態。當第一次登錄頁面時我們可以指定選中GridView裡的第一條記錄的radio button按鈕(默認狀態是沒有一個radio button被選中,就像現在一樣)。為此,我們只需簡單地將if (SuppliersSelectedIndex == e.Row.RowIndex) 改成if (SuppliersSelectedIndex == e.Row.RowIndex || (!Page.IsPostBack && e.Row.RowIndex == 0)).

  到這一步,我們為GridView創建了一個聚合的radio buttons列。它只允許選中其中的任一條記錄,並在頁面發生回傳後仍處於選中狀態。接下來,我們將顯示某個選中的供應商提供的產品。在第4步,我們將看如何將用戶鏈接到另一個顯示產品的頁面,並傳遞該供應商的SupplierID值;在第5步,我們將探討如何在相同頁面顯示供應商的產品。

  注意:與其用TemplateField模板(在第3步討論的那樣),還不如創建一個自定義的DataControlField class類來構建用戶界面並提供相關功能。DataControlField class是一個基本類,GridView和DetailsView控件中內置的BoundField、CheckBoxField、TemplateField等都源於它。如果創建自定義DataControlField的話,我們可以在聲明代碼中添加radio buttons列,復制其它頁面的函數及應用程序也要容易些。

  如果你在ASP.NET裡創建過自定義控件的話,你應該知道那需要了解更多的知識,並且需要小心處理很多問題。因此,我們目前不用自定義DataControlField class類,還是堅持用TemplateField模板。或許我們將在以後的教程裡探討如何使用自定義DataControlField class類。

第4步:在另一個頁面顯示供應商的產品

  在GridView裡選中一條記錄後,我們需要顯示該供應商的產品。有時候下我們想在另一個頁面顯示產品,而有時候我們想在同一頁面顯示數據。首先,我們探討如何在另一個頁面顯示產品,在第5步,我們將在RadioButtonField.aspx頁面添加一個GridView顯示產品。

  當前,頁面上有2個Button Web控件——ListProducts和SendToProducts。當點擊SendToProducts時,我們希望將用戶鏈接到位於~/Filtering/ProductsForSupplierDetails.aspx的頁面。我們在教程《跨頁面的主/從報表》裡已經創建了該頁面,供應商的SupplierID是由一個名為SupplierID的querystring field傳遞的。

  為提供該功能,我們為SendToProducts的Click事件創建事件處理器。在第3步,我們添加了SuppliersSelectedIndex屬性,用於返回所選行記錄的index值。在如下代碼中,相應的SupplierID可以從GridView控件的DataKeys集合獲取,並轉到~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID using Response.Redirect("url")頁面。

protected void SendToProducts_Click(object sender, EventArgs e)
{
 // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
 int supplierID = 
  Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
 Response.Redirect(
  "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
  + supplierID);
 }
}

  當在GridView控件裡選中一個radio button時,以上代碼運行正常。但是,如果最開始GridView裡沒有任何radio buttons被選中,而用戶又點擊了SendToProducts按鈕,SuppliersSelectedIndex就會賦值為-1,這將會拋出一個異常,因為在DataKeys集合裡沒有index為-1的情況。不過沒有關系,就像在第3步中探討的一樣,修改RowCreated事件處理器,使GridView默認選中第一個radio button。

  為了應對SuppliersSelectedIndex為-1的情況,我們在GridView上面添加一個Label Web控件,設其ID為ChooseSupplierMsg,CssClass 屬性為Warning,EnableViewState和Visible屬性為false,Text屬性為“Please choose a supplier from the grid.”。定義在Styles.css文件裡的CSS class Warning將文本顯示為紅色、斜體、大號加粗。通過將EnableViewState和Visible屬性設置為false,該Label控件將不可見,除非在某些頁面回傳時,我們有意地通過編程將其Visible屬性設置為true。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450691.gif
圖13:在GridView控件上添加一個Label Web控件

  接著,在Click事件處理器裡添加代碼,如果SuppliersSelectedIndex的值小於0時Label控件ChooseSupplierMsg將可見,並將用戶直接鏈接到~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID頁面:

protected void SendToProducts_Click(object sender, EventArgs e)
{
 // make sure one of the radio buttons has been selected
 if (SuppliersSelectedIndex < 0)
  ChooseSupplierMsg.Visible = true;
 else
 {
  // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
  int supplierID = 
   Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
  Response.Redirect(
   "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
   + supplierID);
 }
}

  在浏覽器裡訪問該頁面,在不選供應商的情況下點擊SendToProducts按鈕,如圖14所示,label控件ChooseSupplierMsg變為可見了。然後,選擇一個供應商,再單擊SendToProducts按鈕,這會將你鏈接到一個顯示該供應商產品的頁面。圖15顯示了當選擇供應商Bigfoot Breweries時,ProductsForSupplierDetails.aspx
頁面的情況。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450767.gif
圖14:未選供應商時,Label控件ChooseSupplierMsg為可見

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450791.gif
圖15:ProductsForSupplierDetails.aspx頁面顯示了供應商的產品

第5步:在本頁顯示所選供應商的產品

  在第4步,我們探討了怎樣在另一頁面顯示供應商的產品,另外我們也可以在本頁面顯示產品。鑒於此,我們在RadioButtonField.aspx頁面添加另一個GridView控件展示所選供應商的產品。

  一旦選擇一個供應商後,我們只想在GridView裡顯示該供應商的產品。在名為Suppliers的GridView控件下,添加一個Panel Web控件,設其ID為ProductsBySupplierPanel,將Visible屬性設置為false,text屬性設置為“Products for the Selected Supplier”, 緊接著添加一個名為ProductsBySupplier的GridView控件。在其智能標簽裡,將其綁定到一個名為ProductsBySupplierDataSource的ObjectDataSource控件。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450853.gif
圖16:將GridView控件ProductsBySupplier綁定到一個新的ObjectDataSource

   然後,將設置該ObjectDataSource使用ProductsBLL類。由於我們只想獲取一個供應商的產品數據,指定該ObjectDataSource控件調用GetProductsBySupplierID(supplierID)方法,同時在UPDATE, INSERT和DELETE選項卡的下拉列表裡選“(None)” 。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916450874.gif
圖17:指定該ObjectDataSource控件調用GetProductsBySupplierID(supplierID)方法

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916451598.gif
圖18:在UPDATE, INSERT和DELETE選項卡的下拉列表裡選“(None)”

  完成對SELECT, UPDATE, INSERT和DELETE選項卡的設置後,點下一步。因為GetProductsBySupplierID(supplierID)方法需要一個輸入參數,因此向導提示我們指定參數值的來源。

  我們有幾種選擇指定參數值來源。我們可以使用默認值,也可以在ObjectDataSource控件的Selecting事件處理器裡,通過編程的方式,用SuppliersSelectedIndex屬性的值對Parameter的DefaultValue屬性賦值。可以在前面的教程《編程設置ObjectDataSource的參數值》裡溫習相關內容。

  此外,我們可以使用一個ControlParameter,它涉及到名為Suppliers的GridView控件的SelectedValue屬性(見圖19)。GridView控件的SelectedValue屬性將返回與SelectedIndex屬性相匹配的DataKey值。為此,當點擊ListProducts按鈕時,我們將編程把GridView控件的SelectedIndex屬性設置為選中的那行記錄。另外設置了SelectedIndex後,選中的記錄將運用定義在DataWebControls主題中的SelectedRowStyle(顯示為黃色背景)。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916452106.gif
圖19:用一個ControlParameter當參數源來指定GridView的SelectedValue值

  完成向導後,Visual Studio將自動添加產品的數據域(data fields)。將除了ProductName, CategoryName和UnitPrice外的其它列全部刪除,並將HeaderText屬性分別設為“Product”, “Category”和“Price”。再將UnitPrice列格式化為貨幣形式。完成上述修改後,Panel, GridView和ObjectDataSource的聲明代碼看起來應該像下面的差不多:

<asp:Panel runat="server" ID="ProductsBySupplierPanel" Visible="False">
 <h3>
  Products for the Selected Supplier</h3>
 <p>
  <asp:GridView ID="ProductsBySupplier" runat="server" 
   AutoGenerateColumns="False" DataKeyNames="ProductID"
   DataSourceID="ProductsBySupplierDataSource" EnableViewState="False">
   <Columns>
    <asp:BoundField DataField="ProductName" HeaderText="Product" 
     SortExpression="ProductName" />
    <asp:BoundField DataField="CategoryName" HeaderText="Category" 
     ReadOnly="True" SortExpression="CategoryName" />
    <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
     HeaderText="Price" HtmlEncode="False" 
     SortExpression="UnitPrice" />
   </Columns>
  </asp:GridView>
  <asp:ObjectDataSource ID="ProductsBySupplierDataSource" runat="server" 
   OldValuesParameterFormatString="original_{0}"
   SelectMethod="GetProductsBySupplierID" TypeName="ProductsBLL">
   <SelectParameters>
    <asp:ControlParameter ControlID="Suppliers" Name="supplierID" 
     PropertyName="SelectedValue" Type="Int32" />
   </SelectParameters>
  </asp:ObjectDataSource>
 </p>
</asp:Panel>

  當點擊ListProducts按鈕時,我們需要將GridView的SelectedIndex屬性設置為SelectedSuppliersIndex,並將Panel控件ProductsBySupplierPanel的Visible屬性設置為true。為ListProducts按鈕的Click事件創建事件處理器,添加如下代碼:

protected void ListProducts_Click(object sender, EventArgs e)
{
 // make sure one of the radio buttons has been selected
 if (SuppliersSelectedIndex < 0)
 {
  ChooseSupplierMsg.Visible = true;
  ProductsBySupplierPanel.Visible = false;
 }
 else
 {
  // Set the GridView's SelectedIndex
  Suppliers.SelectedIndex = SuppliersSelectedIndex;
  // Show the ProductsBySupplierPanel panel
  ProductsBySupplierPanel.Visible = true;
 }
}

  如果沒有從GridView裡選擇供應商,Label控件ChooseSupplierMsg將顯示出來,而Panel控件ProductsBySupplierPanel則不可見。反之,如果選擇了一個供應商,ProductsBySupplierPanel將顯示出來,並且GridView的SelectedIndex屬性將更新。

圖20為選擇供應商Bigfoot Breweries並單擊“Show Products on Page”按鈕後的效果圖。

 https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017010916452253.gif
圖20:在本頁顯示供應商Bigfoot Breweries的產品

總結:

  就像在教程《使用 GridView和DetailView實現的主/從報表》裡探討的一樣,如果在GridView裡使用一個CommandField,並設置其ShowSelectButton屬性為true,我們就可以在GridView裡選擇記錄。但是CommandField僅僅將其按鈕顯示為常規的button, link或image。在一個只能選擇一條記錄的用戶界面裡,要為每一個GridView row提供一個radio button或checkbox。本教程探究了如何添加一個radio button列。

  然而,添加一個radio button列並沒有想像的那麼容易。沒有內置的RadioButtonField供我們添加;在模板裡使用RadioButton Web控件也會引發其它的問題。要創建這種用戶界面,我們要麼創建自定義的DataControlField類,要麼在RowCreated事件裡將適當的HTML注入模板。

  在探討了如何添加radio buttons列後,我們將注意力轉向添加checkboxes列。使用checkboxes列的話,用戶可以選擇一條或多條GridView rows並執行相同的操作。(比如在郵箱裡,我們同時選擇多封郵件並將之刪除)。在接下來的教程裡我們看如何來實現。

  祝編程快樂!

作者簡介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創始人,自1998年以來一直應用 微軟Web技術。大家可以點擊查看全部教程《[翻譯]Scott Mitchell 的ASP.NET 2.0數據教程》,希望對大家的學習ASP.NET有所幫助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved