为 GridView 添加一列单选按钮50

简介

GridView 控件提供多种内置功能。它含有多个显示文本、图像、超链接和按钮的不同字段。它还支持模板的进一步定制。只需轻轻的点击几下鼠标,您即可构造 GridView ,使其每行均可使用按钮进行选择,或者启用编辑或删除功能。尽管它提供了多种功能,但是很多情况下我们仍然需要添加一些附加功能和它不支持的功能。在本教程和接下来的两篇教程中,我们将探讨如何增强 GridView 的功能,使之包含更多的附加功能。

本教程和下一个教程重点探讨如何增强选行流程。正如在 使用具有 Details DetailView 功能的可选主 GridView 的主/ 明细报表 中讨论的一样 , 我们可以向GridView 添加CommandField , 该 CommandField 包含一个 Select 按钮。单击后紧接着会回传 , 并且 GridView 的 SelectedIndex 属性将更新到行索引 , 此行的 Select 按钮为被点击的按钮。在 使用具有 Details DetailView 功能的可选主 GridView 的主/ 明细报表 教程中 , 我们了解了如何使用此功能显示选定 GridView 行的详细情况。 ,

尽管 Select 按钮适用于多种情况,但是它可能并不适用于其它情况。并不经常使用按钮,而是通常使用其它两个用户界面元素来进行选择:单选按钮和复选框。我们可添加一个 GridView ,代替 Select 按钮,从而保证每行均包含一个单选按钮或者复选框。在用户仅可选择 GridView 记录中的一条记录的情况下,单选按钮可能要优于 Select 按钮。在用户可选择多条记录的情况下(例如基于 web 的电子邮件程序,用户可能希望选择删除多条信息),复选框可提供 Select 按钮和单选按钮用户界面无法提供的功能。

本教程将探讨如何向 GridView 添加一列单选按钮。下个教程还将探讨如何使用复选框。 .

步骤1 : 创建增强 GridView 的 Web 页面

在我们开始增强 GridView 功能 , 使之包含一列单选按钮之前 , 我们首先花点时间在我们的网站项目中创建本教程和下两个教程需要的ASP.NET 页面。首先 , 添加一个名为 EnhancedGridView 的新文件夹。接下来 , 将以下 ASP.NET 页面添加到该文件夹 , 确保每个页面与 Site.master 主页面相关联 :

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

图1 : 为 SqlDataSourc 相关教程添加 ASP.NET 页

与其它文件夹一样 ,EnhancedGridView 文件夹中的 Default.aspx 页将列出教程。回想一下 ,SectionLevelTutorialListing.ascx 用户控件提供本功能。因此 , 请通过从Solution Explorer 中将此 用户 控件拖放到页面的 Design 视图来添加此 用户 控件。

图2 : 将SectionLevelTutorialListing.ascx 用户控件添加至 Default.aspx

最后 , 将这四个页面按条目添加到 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>

更新Web.sitemap 后 , 花点时间用浏览器查看一下教程网站。现在,左边的菜单包含用于编辑、插入和删除教程的各项。

图3 : 现在 , 网站地图中包含了增强 GridView 教程的条目

步骤2 : 在GridView 中显示供应商

在本教程中 , 我们将创建一个列出美国供应商的 GridView , 每个 GridView 行均提供了一个单选按钮。在使用单选按钮选择一个供应商之后,用户可以单击按钮查看供应商的产品。尽管此任务似乎微不足道,但是存在一些微妙之处,使它变得非常棘手。 在我们深入研究这些微妙之处之前,我们首先获得一个列出供应商的 GridView 。

首先 , 通过将GridView 从工具箱拖放到设计器中 , 在 EnhancedGridView 文件夹中打开RadioButtonField.aspx 页。将 GridView 的 ID 设置为 Suppliers , 从其智能标记中 , 选择创建新数据源。具体地说 , 创建一个名为SuppliersDataSource 的 ObjectDataSource ,ObjectDataSource 从 SuppliersBLL 对象提取数据。

图4 : 创建一个名称为 SuppliersDataSource 的新的 ObjectDataSource

 

图5 : 配置 ObjectDataSource , 使之使用 SuppliersBLL 类

由于我们只希望列出美国的供应商 , 因此 , 请从SELECT 选项卡的下拉列表中选择 GetSuppliersByCountry(country) 方法。

图6 : 配置 ObjectDataSource , 使之使用 SuppliersBLL 类

从UPDATE 选项卡选择 “(None)” 选项 , 并单击Next 。

图7 : 配置 ObjectDataSource , 使之使用 SuppliersBLL 类

由于GetSuppliersByCountry(country) 方法可接受参数 ,Configure Data Source 向导将提示我们输入这个参数的源。要想指定固定值 ( 此例中为 “USA” ), 请保留 Parameter source 下拉列表的None 设置 , 并在文本框中输入默认值。单击 Finish 完成向导。

图8 : 使用 “USA” 作为国家参数的默认值

完成向导之后 ,GridView 将为每个供应商数据字段包含一个BoundField 。删除 CompanyName 、City 和 Country BoundField 之外的所有 BoundField , 并把 CompanyName BoundFields 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>

在本教程中 , 我们允许用户在供应商列表或者其它页面上查看选定供应商的产品。要达到这一目的,请在页面上添加两个 Web 按钮控件。我已经将这两个Web 按钮 的 ID 设置为 ListProducts 和SendToProducts , 我的想法是:单击 ListProducts 时将出现回传 , 并且选定供应商的产品将被列在同一个页面上 , 但是 , 单击 SendToProduct 时 , 用户将被转到其它列出产品的页面上。

图9 显示通过浏览器查看页面时 , 页面上显示了 Suppliers GridView 和两个Web 按钮 控件。

图9 : 页面上列出了美国供应商的名称、城市和国家信息

步骤3 : 添加一列单选按钮

此时 ,Suppliers GridView 有三个 BoundField , 分别显示美国供应商的公司名称、城市和国家。但是 , 它还缺少一列单选按钮。遗憾的是 ,GridView 不包含内置的 RadioButtonField , 否则我们可以向网格中添加 RadioButtonField , 并完成这项工作。或者 , 我们可以添加一个TemplateField , 并将其 ItemTemplate 配置为提供单选按钮 , 从而为每个GridView 行添加单选按钮。

最初 , 我们可能假定所需的用户界面可以通过向TemplateField 的 ItemTemplate 添加一个 RadioButton Web 控件来实现。尽管这样实际上会向 GridView 的每一行都添加一个单选按钮,这些单选按钮不能分组,因此并不互相排斥。也就是说,最终用户可以同时从 GridView 选择多个单选按钮。

尽管使用RadioButton Web 控件的TemplateField 不提供我们所需的功能 , 我们还是要采用这种方式 , 因为它可以检查造成单选按钮不被分组的原因 , 因此是值得的。首先 , 向Suppliers GridView 添加一个 TemplateField , 使其成为最左边的字段。接下来 , 从GridView 的智能标记单击 Edit Templates 链接 , 并将RadioButton Web 控件从文本框拖放到 TemplateField 的 ItemTemplate ( 见图10 )。 将RadioButton 的 ID 属性设置为 RowSelector , 将 GroupName 属性设置为SuppliersGroup 。

图10 : 向 ItemTemplate 添加 RadioButton Web 控件

使用设计器完成添加操作之后 ,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 属性用于指定呈现的单选按钮的名称属性值。浏览器检查单选按钮的名称属性值,确定单选按钮的分组。

将RadioButton Web 控件添加到 ItemTemplate 之后 , 请通过浏览器访问此页面 , 并单击网格行中的单选按钮。请注意单选按钮并未分组,因此可选择所有的行,如图 11 所示。

图11 :GridView 的单选按钮并未分组

单选按钮并未分组的原因是它们呈现的名称属性值不同 , 尽管它们具有相同的GroupName 属性设置。要查看这些区别,在浏览器中选择 View/Source ,并检查单选按钮标记:

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

请注意 , 名称和ID 属性的值与 Properties 窗口中指定的值并不完全相同 , 而是预置了一些其它 ID 值。添加到呈现的 ID 和名称属性前头的附加 ID 值是单选按钮父控件的 ID – GridViewRows 的 ID 、GridView 的 ID 、Content 控件的 ID 和Web Form 的 ID 。添加这些 ID 是为了保证 GridView 中每个呈现的 Web 控件具有唯一的 ID 值和名称值。

每个呈现的控件需要具有不同的名称和ID , 因为这是浏览器在客户端区分每个控件以及在回传时确定网络服务器发生什么操作或者更改的唯一途径。例如,我们假设:一旦 RadioButton 的选定状态发生变更,希望运行某些服务器端代码。我们可以通过将RadioButton 的 AutoPostBack 属性设置为 True , 并为 CheckChanged 事件创建 Event Handler 来实现这一目标。但是,如果所有单选按钮呈现的名称和 ID 值都相同,回传时我们将无法确定到底单击了哪个特定的 RadioButton 。

总之 , 我们不能使用RadioButton Web 控件在 GridView 中创建一列单选按钮。而且 , 我们必须使用相当陈旧的技术保证标记被注入到每个GridView 行。

注意 : 和 RadioButton Web 控件一样,单选按钮 HTML 控件在添加到模板时将包含唯一的名称属性,保证网格中单选按钮未进行分组。如果您不熟悉HTML 控件 , 您可以按照您的意愿忽略本提示 , 因为HTML 控件很少使用 , 尤其是在 ASP.NET 2.0 中。但是如果您愿意了解更多内容 , 请参照 K. Scott Allen 的博客日志 Web Controls and HTML Controls 。

使用Literal 控件插入单选按钮标记

为了能够将GridView 内的所有单选按钮正确分组 , 我们需要手工将单选按钮的标记插入 ItemTemplate 。每个单选按钮需要相同的名称属性,但是,每个单选按钮应该具有唯一的 ID 属性(假如我们希望通过客户端脚本访问单选按钮)。在用户选定单选按钮,并回传页面时,浏览器将送回选定单选按钮的 value 属性的值。因此,每个单选按钮需要具有唯一的 value 属性。最后,我们需要在回传时确保将 checked 属性添加到选定的单选按钮,否则,在用户完成选择并回传时,单选按钮将返回到它们的默认状态(全部取消选定)。

可以采用两种方式将低级标记插入到模板中。第一种方式是组合标记 , 并调用 代码文件 类中定义的格式化方法。该方法首次提及是 在 GridView控件中使用 TemplateField 教程中。在我们的例子中 , 它可能类似如下 :

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

此处 ,GetUniqueRadioButton 和 GetRadioButtonValue 为 代码文件 类中定义的方法 ,它们 返回每个单选按钮的相应的 ID 和 value 属性的值。这种方法非常适用于分配id 和 value 值 , 但是在需要指定 checked 属性值时就不管用了 , 因为数据绑定语法仅当数据首次绑定到GridView 时才执行。因此,如果 GridView 启用了视图状态,格式化方法将仅在首次加载页面时(或者在 GridView 明确绑定到数据源时)才会触发,因此,在回传时不会调用设置 checked 属性的函数。这是一个非常棘手的问题,并有些超出本文的范围,所以本文不再讨论。但是,我推荐你们尝试一下使用上述方法,并进行到遇到困难为止。尽管这样的练习与使用版本还有一段距离,但它仍然会加深您对 GridView 和数据绑定生命周期的理解。

向模板中插入定制的低级标记的另外一种方法 ( 在本教程中使用的方法 ) 是向模板添加 Literal 控件 。然后 ,可以通过 在 GridView 的 RowCreated 或 RowDataBound Event Handler 中编码来访问 Literal 控件 , 并将其 Text 属性设置为要传输的标记。

首先 , 从TemplateField 的 ItemTemplat 删除RadioButton , 并替换为 Literal 控件。将 Literal 控件的 ID 设置为 RadioButtonMarkup 。

图12 :向 ItemTemplate 添加 Literal 控件

接下来 , 为GridView 的 RowCreated 事件创建Event Handler 。无论数据是否重新绑定到 GridView , 添加每一行时均将触发 RowCreated 事件。这意味着既使从视图状态重新加载数据产生回传时 , 仍会触发RowCreated , 这也是我们使用 RowCreated 而不用 RowDataBound 的原因 (RowDataBound 只有在数据明确绑定到 Web 数据 控件时才会触发 ) 。

在此 Event Handler 中 , 我们希望仅在我们处理数据行时才运行。对于每个数据行来说 , 我们希望通过编码引用 RadioButtonMarkup Literal 控件 , 并将其 Text 属性设置为要传输的标记。正如下列代码所示 , 传输的标记将创建一个单选按钮 , 此单选按钮的名称属性设置为 SuppliersGroup ,id 属性设置为 RowSelectorX , 其中 X 为 GridView 行的索引 , 并且其 value 属性被设置为 GridView 行的索引。

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 。因此 , 人们不禁会认为每个单选按钮的值应为实际SupplierID ( 而不是 GridView 行的索引 ) 。尽管在某些情况下的确如此 , 但是 , 盲目的接受和处理 SupplierID 可能在安全性方面存在风险。例如 ,我们要求 GridView 仅列出了美国的供应商。但是 , 如果直接从单选按钮传递 SupplierID , 我们将如何阻止捣乱的用户对回传时发回的SupplierID 值造假呢 ? 通过使用行索引值 , 然后在回传时从DataKeys 集合获取 SupplierID 值 , 我们可以保证用户仅使用与某一 GridView 行关联的 SupplierID 值。

在添加完成此Event Handler 代码后 , 请花点时间在浏览器中测试该页面。首先,请注意每次只能在网格中选择一个单选按钮。但是,当选择一个单选按钮,并单击某个按钮时,将出现回传,并且单选按钮全部恢复到它们的初始值(也就是说,在回传时,选定的单选按钮已经不再选定)。要解决这个问题 , 我们需要扩充RowCreated Event Handler , 使其检查从回传发送的选定单选按钮的索引 , 并向传输的匹配行索引标记添加checked="checked" 属性。

出现回传时,浏览器将送回选定单选按钮的名称和值。单选按钮值可以通过编码使用Request.Form("name") 进行检索。Request.Form 属性 提供了一个 NameValueCollection 来代表表格变量。表格变量为 web 页面上的表格字段的名称和值,并且在回传时由 web 浏览器发回。由于 GridView 中呈现的单选按钮的 name 属性为 SuppliersGroup ,web 页面回传时 , 浏览器将把 SuppliersGroup=valueOfSelectedRadioButton 回传到web 服务器 ( 与其它表格字段一起 ) 。然后 , 此信息可从 Request.Form 属性访问 , 使用的访问方式为 : Request.Form("SuppliersGroup")。

由于我们需要不仅在 RowCreated Event Handler 中确定选定单选按钮索引 , 而且还要在 Web 按钮控件的 Click Event Handler 确定 ,因此 我们需要向 代码文件 类添加一个SuppliersSelectedIndex 属性 , 该属性在单选按钮未选定时返回-1 , 在选定某个单选按钮时返回选定的索引。

private int SuppliersSelectedIndex 

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

添加该属性之后 , 当SuppliersSelectedIndex 等于e.Row.RowIndex 时 , 我们要在 RowCreated Event Handler 中添加checked="checked" 标记。 更新 Event Handler 使其包含下列逻辑:

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 += " />"; 
    } 
}

完成这一更改后 , 选定的单选按钮在回传后将保持选定。现在,我们具备了指定选定单选按钮的能力,我们可以更改行为,从而在首次访问页面时选定第一个 GridView 行的单选按钮(而不是默认情况下不选择任何单选按钮)。要默认选定第一个单选按钮 , 请将if SuppliersSelectedIndex = e.Row.RowIndex 语句更改为下列形式 :If SuppliersSelectedIndex = e.Row.RowIndex OrElse (Not Page.IsPostBack AndAlso e.Row.RowIndex = 0) Then 。

此时 , 我们已经向GridView 添加了一列分组单选按钮 , 分组单选按钮允许选择单个 GridView 行 , 并在回传时进行记录。下一步是显示选定供应商的产品。在步骤 4 中,我们将了解如何将用户重定向到其它页面,发送选定的 SupplierID 。在步骤 5 中,我们将了解如何在相同页面的 GridView 中显示选定供应商的产品。

注意 : 我们可以创建一个显示适当的用户界面和功能的定制DataControlField 类 , 而不是使用 TemplateField ( 这是稍显冗长的步骤 3 重点介绍的 ) 。 DataControlField 类 是基类 ,BoundField 、CheckBoxField 、TemplateField 和其它内置 GridView 和 DetailsView 字段均从其派生出来。创建一个定制 DataControlField 类意味着只使用声明语法就可添加单选按钮列 , 并且可以方便地在其它web 页面和其它 web 应用程序上重用此功能。

如果您曾经在 ASP.NET 中创建过定制、编译控件 , 那么 , 您会知道这个过程需要数量可观的琐碎工作 , 以及必须小心处理多个微妙问题和边缘情况。因此 , 这里我们放弃通过定制 DataControlField 类的方案实施单选按钮列 , 坚持选择使用 TemplateField 。可能在后续教程中我们有机会探讨创建、使用和部署定制 DataControlField 类。

步骤4 : 在单独页面上显示选定供应商的产品

在用户选定GridView 行之后 , 我们需要显示选定供应商的产品。在某些情况下,我们可能希望在单独的页面上显示这些产品,而在另外的一些情况下,我们更希望在同一个页面上显示这些产品。我们首先探讨如何在单独页面上显示产品;在步骤 5 中,我们将了解向 RadioButtonField.aspx 添加 GridView 来显示选定供应商的产品。

目前 , 页面上有两个Web 按钮 控件 – ListProducts 和 SendToProducts 。单击 SendToProducts Button 时 , 我们希望将用户转到 ~/Filtering/ProductsForSupplierDetails.aspx 。此页面是在 跨两页面的主/ 明细筛选 教程中创建的,用于显示其 SupplierID 通过名为 SupplierID 的 querystring 字段传递的供应商的产品。

要提供此功能 , 需要为 SendToProducts Button 的 Click 事件创建一个 Event Handler 。在步骤 3 中 , 我们添加了 SuppliersSelectedIndex 属性 , 该属性返回选定单选按钮行的索引。相应的SupplierID 可从 GridView 的 DataKeys 集合进行检索 , 并且可使用Response.Redirect("url") 将用户转到 ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID 。

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 选中一个单选按钮 , 本代码即可顺利工作。起初 , 如果GridView 没有选定任何单选按钮 , 并且用户点击了 SendToProducts 按钮 , 则SuppliersSelectedIndex 的值将为 -1 , 这将引发抛出一个异常 , 因为 -1 超出了 DataKeys 集合索引的范围。这并不是我们关心的问题 , 但是 , 如果您决定像步骤 3 中讨论的那样更新 RowCreated Event Handler , 初始就会在GridView 中选定第一个单选按钮。

要使解决SuppliersSelectedIndex 的值为 -1 的问题, 请在 GridView 的上方向页面上添加一个 Web 标签 控件。将其 ID 属性设置为 ChooseSupplierMsg 、CssClass 属性设置为 Warning 、EnableViewState 和Visible 属性设置为 False 、Text 属性设置为 “Please choose a supplier from the grid” 。CSS 类在 Styles.css 中定义 , 并以红色、斜体、粗体和大字体文本显示警告信息。通过将其 EnableViewState 和 Visible 属性设置为 False ,除非控件的 Visible 属性通过编码设置为 True ,否则将不会呈现 Label 。

图13 : 在 GridView 上方添加一个 Web 标签 控件

接下来 , 扩充 Click Event Handler , 使之在SuppliersSelectedIndex 小于零的情况下显示ChooseSupplierMsg Label , 否则将用户重定位到~/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); 
    } 
}

在浏览器中访问该页面,并在从GridView 选择供应商之前单击 SendToProducts 按钮。如图 14 所示 , 这将显示 ChooseSupplierMsg label 。接下来,选择一个供应商,并单击 SendToProducts 按钮。这将快速链接到列出选定供应商提供的产品的页面。图 15 显示了选定 Bigfoot Breweries 供应商时的 ProductsForSupplierDetails.aspx 页面。

图14 : 在未选定供应商的情况下显示 ChooseSupplierMsg Label

图15 :ProductsForSupplierDetails.aspx 页面上显示了选定供应商的产品

步骤5 :在同一页面上显示选定供应商的产品

在步骤4 中 , 我们了解了如何将用户转到其它 web 页 , 从而显示选定供应商的产品。或者,也可以在同一页面上显示选定供应商的产品可。为了说明这一点,我们将向 RadioButtonField.aspx 页面添加另外一个 GridView ,从而显示选定供应商的产品。

由于我们希望GridView 上的产品在选定供应商时显示 , 因此 , 需要在 Suppliers GridView 的下方添加一个 Panel Web 控件 , 将其ID 设置为 ProductsBySupplierPanel 、Visible 属性设置为 False 。在 Panel 内 , 添加文本 “Products for the Selected Supplier” , 其后面为名为ProductsBySupplier 的 GridView 。从 GridView 的智能标记 , 选择将其绑定到一个名为ProductsBySupplierDataSource 的新ObjectDataSource 。

图16 : 将 ProductsBySupplier GridView 绑定到一个新的 ObjectDataSource

接下来 , 将ObjectDataSource 配置为使用 ProductsBLL 类。由于我们仅希望检索选定供应商提供的产品 , 请指定ObjectDataSource 应调用GetProductsBySupplierID(supplierID) 方法来检索数据。在 UPDATE 、 INSERT 和 DELETE 选项卡中将下拉列表中选择为 “(None)” 。

 

图17 : 将 ObjectDataSource 配置为使用GetProductsBySupplierID(supplierID) 方法

图18 : 在 UPDATE 、INSERT 和 DELETE 选项卡中将下拉列表设置为 “(None)”

在配置完SELECT 、UPDATE 、INSERT 和 DELETE 选项卡之后 , 单击 Next 。由于 GetProductsBySupplierID(supplierID) 方法需要输入参数 ,Create Data Source 向导将提示我们指定参数值的来源。

此处 , 我们有几个选项来指定参数值的来源。我们可以使用默认的Parameter 对象 , 并且在 ObjectDataSource 的 Selecting Event Handler 中通过编码将 SuppliersSelectedIndex 属性值分配给Parameter 的 DefaultValue 属性。请参阅 通过编码设定 ObjectDataSource 参数值 教程, 复习通过编码向 ObjectDataSource 参数分配参数值的内容。

或者 , 我们可以使用ControlParameter , 请参阅Suppliers GridView 的 SelectedValue 属性 ( 见图 19 ) 。GridView 的 SelectedValue 属性返回对应于 SelectedIndex 属性 的 DataKey 值。为了保证此选项能够正常工作 , 我们需要在单击 ListProducts 按钮时将 GridView 的 SelectedIndex 属性通过编码设置为选定行。作为附带的好处 , 通过设置 SelectedIndex , 选定记录将呈现为 DataWebControls Theme 中 定义的 SelectedRowStyle ( 黄色背景 ) 。

图19 : 使用 ControlParameter 指定 GridView 的 SelectedValue 作为参数源

完成向导之后 ,Visual Studio 将自动为产品的数据字段添加字段。删除ProductName 、CategoryName 和 UnitPrice BoundField 之外的所有 BoundField , 将HeaderText 属性设置为 “Product” 、“Category” 和 “Price” 。配置 UnitPrice BoundField , 保证其值以货币形式出现。作出这些更改后 ,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 , 将ProductsBySupplierPanel Pane 的Visible 属性设置为 True 。要达到这个目的 , 请为 ListProducts Web 按钮 控件的Click 事件创建一个 Event Handler , 并添加下列代码 :

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

如果未从GridView 选定供应商 , 页面上将显示 ChooseSupplierMsg Label , 而ProductsBySupplierPanel Panel 将隐藏。否则 , 如果已经选定供应商 , 则页面上将显示 ProductsBySupplierPanel , 并且更新 GridView 的SelectedIndex 属性。

图20 显示了选定 Bigfoot Breweries 供应商 , 并且单击“Show Products on Page” 按钮之后的结果。

图20 : 在同一页面上列出了 Bigfoot Breweries 提供的产品

小结

正如在 使用具有 Details DetailView 功能的可选主GridView 的主/明细报表 教程中讨论的一样 , 可使用其ShowSelectButton 属性设置为 true 的 CommandField 从 GridView 选择记录。但是, CommandField 的按钮既可作为正常的按钮和链接显示,也可作为图像显示。另一个选行用户界面是在每个 GridView 行中提供一个单选按钮或一个复选框。在本教程中,我们探讨了如何添加一列单选按钮。

遗憾的是 , 添加一列单选按钮并非人们期望的那样直接或简单。单击按钮时并没有任何可添加的内置RadioButtonField , 并且在TemplateField 中使用RadioButton Web 控件会引入一系列问题。最后 , 要想提供这样的界面 , 我们必须创建一个定制 DataControlField 类 , 或者在 RowCreated 事件期间向TemplateField 插入适当的 HTML 代码。

我们已经探讨了如何添加一列单选按钮,下面我们将把注意力集中到添加一列复选框上面。通过一列复选框,用户可以选择一个或者多个 GridView 行,然后对所有选定行完成某些操作(例如,从基于 web 的邮件客户端选择一系列邮件,然后选择删除所有选定的邮件)。在下个教程中,我们将探讨如何添加复选框列。

快乐编程!

 

posted @ 2016-05-01 23:40  迅捷之风  阅读(1291)  评论(0编辑  收藏  举报