添加 GridView 单选按钮列 (C#)

作者 :Scott Mitchell

下载 PDF

本教程介绍如何向 GridView 控件添加单选按钮列,以便为用户提供更直观的 GridView 单行选择方式。

简介

GridView 控件提供了大量内置功能。 它包含用于显示文本、图像、超链接和按钮的多个不同字段。 它支持用于进一步自定义的模板。 单击鼠标即可创建 GridView,其中每一行都可以通过按钮选择,或者启用编辑或删除功能。 尽管提供了大量功能,但经常会出现需要添加其他不受支持的功能的情况。 在本教程和接下来的两个教程中,我们将探讨如何增强 GridView 功能以包含其他功能。

本教程和下一个教程重点介绍如何增强行选择过程。 如 使用带有 DetailsView 的可选主网格视图的母版/详细信息中所述,我们可以将 CommandField 添加到包含“选择”按钮的 GridView。 单击后,将回发,GridView 的 SelectedIndex 属性将更新为单击了“选择”按钮的行的索引。 在 大纲/详细信息使用带有详细信息视图的可选主网格 视图教程中,我们了解了如何使用此功能显示所选 GridView 行的详细信息。

虽然“选择”按钮在很多情况下都有效,但它可能不适用于其他人。 其他两个用户界面元素通常用于选择,而不是使用按钮:单选按钮和复选框。 我们可以扩充 GridView,以便每行包含一个单选按钮或复选框,而不是“选择”按钮。 在用户只能选择其中一条 GridView 记录的情况下,单选按钮可能优先于“选择”按钮。 在用户可能选择多个记录(例如在基于 Web 的电子邮件应用程序中)的情况下,用户可能希望选择多封邮件以删除复选框,而“选择”按钮或单选按钮用户界面中提供的功能是不可用的。

本教程介绍如何将单选按钮列添加到 GridView。 本教程介绍如何使用复选框。

步骤 1:创建增强 GridView 网页

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

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

为 SqlDataSource-Related 教程添加 ASP.NET 页面

图 1:为 SqlDataSource-Related 教程添加 ASP.NET 页

与其他文件夹中一样, Default.aspx 文件夹中 EnhancedGridView 会列出其部分的教程。 回想一下, SectionLevelTutorialListing.ascx 用户控件提供此功能。 因此,将此用户控件Default.aspx从解决方案资源管理器拖到页面设计视图中,将其添加到 。

将 SectionLevelTutorialListing.ascx 用户控件添加到 Default.aspx

图 2:将 SectionLevelTutorialListing.ascx 用户控件添加到 Default.aspx (单击以查看全尺寸图像)

最后,将这四个页面作为条目添加到 Web.sitemap 文件中。 具体而言,在“使用 SqlDataSource 控件 <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后,请花点时间通过浏览器查看教程网站。 左侧菜单现在包含用于编辑、插入和删除教程的项目。

站点地图现在包含用于增强 GridView 教程的条目

图 3:站点地图现在包含用于增强 GridView 教程的条目

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

在本教程中,让我们生成一个 GridView,其中列出了来自美国的供应商,其中每个 GridView 行都提供一个单选按钮。 通过单选按钮选择供应商后,用户可以通过单击按钮查看供应商的产品。 虽然此任务听起来可能微不足道,但有许多微妙之处使其特别棘手。 在深入探讨这些微妙之处之前,让我们先获取一个列出供应商的 GridView。

首先打开文件夹中的页面RadioButtonField.aspxEnhancedGridView方法是将 GridView 从工具箱拖到Designer。 将 GridView ID 设置为 Suppliers ,并从其智能标记中选择创建新的数据源。 具体而言,请创建一个名为 的 SuppliersDataSource ObjectDataSource,用于从 SuppliersBLL 对象拉取其数据。

创建新的对象DataSource 名为 SuppliersDataSource

图 4:新建名为 SuppliersDataSource 的对象数据源 (单击 以查看全尺寸图像)

“配置数据源 - SuppliersDataSource”窗口的屏幕截图,其中选择了业务对象 SuppliersBLL,并突出显示了“下一步”按钮。

图 5:将 ObjectDataSource 配置为使用 SuppliersBLL 类 (单击以查看全尺寸图像)

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

“配置数据源 - SuppliersDataSource”窗口的屏幕截图,其中打开了“SELECT”选项卡。方法选项 GetSupplierByCountry 处于选中状态,并突出显示了“下一步”按钮。

图 6:将 ObjectDataSource 配置为使用 SuppliersBLL 类 (单击以查看全尺寸图像)

在“更新”选项卡中,选择“ (无) ”选项,然后单击“下一步”。

“配置数据源 - SuppliersDataSource”窗口的屏幕截图,其中打开了“更新”选项卡。选择了“无) ” (方法选项,并突出显示了“下一步”按钮。

图 7:将 ObjectDataSource 配置为使用 SuppliersBLL 类 (单击以查看全尺寸图像)

GetSuppliersByCountry(country)由于 方法接受参数,“配置数据源”向导会提示我们输入该参数的源。 若要 ( USA 指定硬编码值,在此示例中) ,请将“参数源”下拉列表保留设置为“无”,并在文本框中输入默认值。 单击“完成”以完成向导。

使用 USA 作为国家/地区参数的默认值

图 8:使用 USA 作为参数的默认值 country (单击以查看全尺寸图像)

完成向导后,GridView 将包含每个供应商数据字段的 BoundField。 删除除 、 CityCountry BoundFields 外CompanyName的所有属性,并将 CompanyName BoundFields HeaderText 属性重命名为 Provider。 执行此操作后,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 控件添加到页面。 我已将这两个按钮ListProducts的 设置为 IDSendToProducts,其理念是单击 时ListProducts将发生回发,并且所选供应商的产品将列在同一页面上,但单击时SendToProducts,用户将被移动到列出产品的另一个页面。

图 9 显示了 Suppliers 通过浏览器查看时的 GridView 和两个 Button Web 控件。

这些来自美国的供应商列出了其名称、城市和国家/地区信息

图 9:来自美国的供应商列出其名称、城市和国家/地区信息 (单击以查看全尺寸图像)

步骤 3:添加单选按钮列

此时, Suppliers GridView 有三个 BoundField,显示美国每个供应商的公司名称、城市和国家/地区。 但是,它仍然缺少一列单选按钮。 遗憾的是,GridView 不包含内置的 RadioButtonField,否则我们可以将其添加到网格中并完成。 相反,我们可以添加 TemplateField 并将其配置为 ItemTemplate 呈现单选按钮,从而为每个 GridView 行生成一个单选按钮。

最初,我们可以假设可以通过将 RadioButton Web 控件添加到 TemplateField 的 来实现 ItemTemplate 所需的用户界面。 虽然这确实会将单个单选按钮添加到 GridView 的每一行,但单选按钮不能分组,因此不是互斥的。 也就是说,最终用户能够同时从 GridView 中选择多个单选按钮。

尽管使用 RadioButton Web 控件的 TemplateField 不提供所需的功能,但让我们实现此方法,因为值得检查为什么生成的单选按钮未分组。 首先,将 TemplateField 添加到 Suppliers GridView,使其成为最左侧的字段。 接下来,从 GridView 智能标记中,单击“编辑模板”链接,然后将 RadioButton Web 控件从工具箱拖到 TemplateField (ItemTemplate 请参阅图 10) 。 将 RadioButton s ID 属性设置为 RowSelector ,将 GroupName 属性设置为 SuppliersGroup

将 RadioButton Web 控件添加到 ItemTemplate

图 10:将 RadioButton Web 控件添加到 ItemTemplate (单击以查看全尺寸图像)

通过Designer添加这些内容后,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 s GroupName 属性 用于对一系列单选按钮进行分组。 具有相同 GroupName 值的所有 RadioButton 控件都被视为分组控件;一次只能从组中选择一个单选按钮。 属性 GroupName 指定呈现的单选按钮属性 name 的值。 浏览器检查单选按钮 name 属性以确定单选按钮分组。

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

GridView s 单选按钮未分组

图 11:GridView 单选按钮未分组 (单击以查看全尺寸图像)

单选按钮未分组的原因是,尽管其属性设置相同GroupName,但呈现name的属性不同。 若要查看这些差异,请从浏览器执行“视图/源”并检查单选按钮标记:

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

请注意, nameid 属性不是属性窗口中指定的确切值,而是在前面加上许多其他ID值。 添加到呈现idname和属性前面的附加ID值是ID父级控制 GridViewRow s、IDGridView sID、Content 控件 ID和 Web 窗体的单选按钮的 。ID 添加这些 ID ,以便 GridView 中呈现的每个 Web 控件都具有唯 id 一和 name 值。

每个呈现的控件都需要不同的 nameid ,因为这是浏览器在客户端上唯一标识每个控件的方式,以及它如何向 Web 服务器标识在回发时发生的操作或更改。 例如,假设每当 RadioButton 的选中状态发生更改时,我们希望运行一些服务器端代码。 为此,可以将 RadioButton s AutoPostBack 属性设置为 true ,并为 CheckChanged 事件创建事件处理程序。 但是,如果呈现的 nameid 所有单选按钮的值都相同,则回发时无法确定单击了哪个特定的 RadioButton。

简而言之,我们不能使用 RadioButton Web 控件在 GridView 中创建单选按钮列。 相反,我们必须使用相当过时的技术来确保将适当的标记注入到每个 GridView 行中。

注意

与 RadioButton Web 控件一样,单选按钮 HTML 控件在添加到模板时将包含唯 name 一属性,使网格中的单选按钮取消组合。 如果不熟悉 HTML 控件,请随意忽略此注释,因为 HTML 控件很少使用,尤其是在 ASP.NET 2.0 中。 但是,如果你有兴趣了解更多信息,请参阅 K. Scott Allen 的博客文章 Web 控件和 HTML 控件

使用文本控件注入单选按钮标记

为了正确对 GridView 中的所有单选按钮进行分组,需要手动将单选按钮标记注入 到 中 ItemTemplate。 每个单选按钮需要相同的 name 属性,但应具有唯 id 一属性 (以防我们想要通过客户端脚本) 访问单选按钮。 用户选择单选按钮并发回页面后,浏览器将发送回所选单选按钮属性 value 的值。 因此,每个单选按钮都需要一个唯 value 一属性。 最后,在回发时,我们需要确保将 属性添加到 checked 所选的一个单选按钮,否则在用户进行选择并回发后,单选按钮将返回到其默认状态 (所有未选定的) 。

可以通过两种方法将低级别标记注入模板。 一种是混合执行标记和对代码隐藏类中定义的格式设置方法的调用。 在 GridView 控件教程中使用 TemplateFields 中首次讨论了此方法。 在我们的示例中,它可能如下所示:

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

此处, GetUniqueRadioButtonGetRadioButtonValue 将在代码隐藏类中定义的方法,这些方法为每个单选按钮返回适当的 idvalue 属性值。 此方法适用于分配 idvalue 属性,但当需要指定 checked 属性值时,此方法并不有效,因为数据绑定语法仅在数据首次绑定到 GridView 时才执行。 因此,如果 GridView 已启用视图状态,则仅当首次加载页面 (或 GridView 显式重回数据源) 时,才会触发格式设置方法,因此不会在回发时调用设置 checked 属性的函数。 这是一个相当微妙的问题,有点超出了本文的范围,所以我把它留在此。 但是,我确实鼓励你尝试使用上述方法,并把它解决到你会卡住的地步。 虽然此类练习不会让你更接近工作版本,但它将有助于更深入地了解 GridView 和数据绑定生命周期。

在模板中注入自定义的低级别标记的另一种方法是将 Literal 控件 添加到模板中。 然后,在 GridView 或RowCreatedRowDataBound事件处理程序中,可以编程方式访问 Literal 控件,并将其Text属性设置为要发出的标记。

首先,从 TemplateField 中删除 RadioButton, ItemTemplate将其替换为 Literal 控件。 将 Literal 控件 ID 设置为 RadioButtonMarkup

将文本控件添加到 ItemTemplate

图 12:将文本控件添加到 ItemTemplate (单击以查看全尺寸图像)

接下来,为 GridView 事件 RowCreated 创建事件处理程序。 无论 RowCreated 数据是否被反弹到 GridView,该事件都会针对添加的每一行触发一次。 这意味着,即使在从视图状态重新加载数据时回发时, RowCreated 事件仍会触发,这就是我们使用它而不是 RowDataBound (仅在数据显式绑定到数据 Web 控件) 时才触发的原因。

在此事件处理程序中,我们仅希望在处理数据行时继续。 对于每个数据行,我们希望以编程方式引用 RadioButtonMarkup Literal 控件,并将其 Text 属性设置为要发出的标记。 如以下代码所示,发出的标记会创建一个单选按钮,其name属性设置为 SuppliersGroupidRowSelectorX其中 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 回发回的值? 通过使用行索引作为 value,然后从DataKeys集合回发时获取 SupplierID ,我们可以确保用户仅使用与其中一个 SupplierID GridView 行关联的值。

添加此事件处理程序代码后,请花一分钟在浏览器中测试页面。 首先,请注意,一次只能选择网格中的一个单选按钮。 但是,在选择单选按钮并单击其中一个按钮时,会发生回发,并且单选按钮将全部还原到其初始状态 (即,在回发时,所选单选按钮不再) 选中。 若要解决此问题,我们需要扩充事件处理程序, RowCreated 以便它检查从回发发送的所选单选按钮索引, checked="checked" 并将 属性添加到行索引匹配项的发出标记。

发生回发时,浏览器会发送回 name 所选单选按钮的 和 value 。 可以使用 以编程方式检索 Request.Form["name"]值。 属性Request.Form提供表示NameValueCollection窗体变量的 。 表单变量是网页中表单字段的名称和值,每当发生回发时,Web 浏览器会发送回。 由于 GridView 中单选按钮的呈现 name 属性为 SuppliersGroup,因此当网页发回时,浏览器将连同其他窗体字段) (发 SuppliersGroup=valueOfSelectedRadioButton 回 Web 服务器。 然后,可以使用 从 属性访问 Request.Form 此信息: Request.Form["SuppliersGroup"]

由于我们不仅需要在事件处理程序中而且在 RowCreated Button Web 控件的事件处理程序中 Click 确定选定的单选按钮索引,因此,让我们向代码隐藏类添加属性 SuppliersSelectedIndex ,该类在未选择任何单选按钮时返回 ,如果选中了其中一个单选按钮,则返回 -1 所选索引。

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

添加此属性后,我们知道在 等于 e.Row.RowIndexSuppliersSelectedIndexRowCreated事件处理程序中添加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 += " />";
    }
}

进行此更改后,所选单选按钮在回发后保持选中状态。 现在,我们能够指定所选单选按钮,我们可以更改行为,以便在首次访问页面时, (选择第一个 GridView 行单选按钮,而不是默认未选择任何单选按钮,即) 当前行为。 若要默认选择第一个单选按钮,只需将 if (SuppliersSelectedIndex == e.Row.RowIndex) 语句更改为以下内容: if (SuppliersSelectedIndex == e.Row.RowIndex || (!Page.IsPostBack && e.Row.RowIndex == 0))

此时,我们已向 GridView 添加了一列分组单选按钮,允许跨回发选择和记住单个 GridView 行。 后续步骤是显示所选供应商提供的产品。 在步骤 4 中,我们将了解如何将用户重定向到另一个页面,并沿着所选 SupplierID发送 。 在步骤 5 中,我们将了解如何在同一页面上的 GridView 中显示所选供应商的产品。

注意

我们可以创建一个呈现相应用户界面和功能的自定义 DataControlField 类,而不是使用 TemplateField (此冗长步骤 3) 的重点。 DataControlField是派生 BoundField、CheckBoxField、TemplateField 和其他内置 GridView 和 DetailsView 字段的基类。 创建自定义 DataControlField 类意味着只需使用声明性语法即可添加单选按钮列,并且还会大大简化在其他网页和其他 Web 应用程序上复制功能。

但是,如果你曾经在 ASP.NET 中创建了自定义的编译控件,则你知道这样做需要相当多的腿部工作,并附带着许多必须仔细处理的微妙之处和边缘情况。 因此,我们将暂时放弃将单选按钮列作为自定义 DataControlField 类实现,并坚持使用 TemplateField 选项。 也许我们将有机会在将来的教程中探索如何创建、使用和部署自定义 DataControlField 类!

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

用户选择 GridView 行后,我们需要显示所选供应商的产品。 在某些情况下,我们可能需要在单独的页面中显示这些产品,而在另一些情况下,我们可能更希望在同一个页面中显示这些产品。 首先,让我们看看如何在单独的页面中显示产品:在步骤 5 中,我们将了解如何将 GridView 添加到 RadioButtonField.aspx 以显示所选供应商的产品。

目前页面上 ListProducts 有两个按钮 Web 控件 和 SendToProductsSendToProducts单击“按钮”时,我们希望将用户发送到 ~/Filtering/ProductsForSupplierDetails.aspx。 此页面是在“跨两页筛选母版/详细信息筛选”教程中创建的,它显示通过名为 SupplierID的查询字符串字段传递的SupplierID供应商的产品。

若要提供此功能,请为 SendToProducts Button 事件 Click 创建事件处理程序。 在步骤 3 中,我们添加了 SuppliersSelectedIndex 属性,该属性返回选择了单选按钮的行的索引。 可以从 GridView 的集合中检索相应的 SupplierID ,然后可以使用 将用户发送到 ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierIDResponse.Redirect("url")DataKeys

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 事件处理程序,以便最初选择 GridView 中的第一个单选按钮,则这不是问题。

若要容纳 SuppliersSelectedIndex-1,请将标签 Web 控件添加到 GridView 上方的页面。 将其 ID 属性设置为 ChooseSupplierMsg,将其 CssClass 属性设置为 Warning,将其 EnableViewStateVisible 属性设置为 false,其 Text 属性设置为 请从网格中选择供应商。 CSS 类 Warning 以红色、斜体、粗体、大字体显示文本,并在 中 Styles.css定义。 通过将 和 Visible 属性设置为 EnableViewStatefalse,不会呈现 Label,除非只有控件 的 Visible 属性以编程方式设置为 true的回发。

在 GridView 上方添加标签 Web 控件

图 13:在 GridView 上方添加标签 Web 控件 (单击以查看全尺寸图像)

接下来,扩充事件处理程序以Click在小于零时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);
    }
}

在浏览器中访问页面并单击按钮, SendToProducts 然后从 GridView 中选择供应商。 如图 14 所示,它显示了 ChooseSupplierMsg 标签。 接下来,选择供应商并单击按钮 SendToProducts 。 这会将你移动到一个页面,其中列出了所选供应商提供的产品。 图 15 显示了 ProductsForSupplierDetails.aspx 选择 Bigfoot Breweries 供应商时的页面。

如果未选择供应商,则显示 ChooseSupplierMsg 标签

图 14ChooseSupplierMsg 如果未选择供应商,则显示标签 (单击以查看全尺寸图像)

所选供应商的产品显示在ProductsForSupplierDetails.aspx

图 15:所选供应商的产品显示在 ProductsForSupplierDetails.aspx (单击以查看全尺寸图像)

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

在步骤 4 中,我们了解了如何将用户发送到另一个网页以显示所选供应商的产品。 或者,所选供应商的产品可以显示在同一页上。 为了说明这一点,我们将向 添加另一个 GridView RadioButtonField.aspx 以显示所选供应商的产品。

由于我们只希望在选择供应商后显示产品的 GridView,因此在 GridView 下 Suppliers 添加面板 Web 控件,将其 ID 设置为 ProductsBySupplierPanel ,将其 Visible 属性设置为 false。 在面板中,添加文本“所选供应商的产品”,后跟名为 的 ProductsBySupplierGridView。 在 GridView 智能标记中,选择将其绑定到名为 ProductsBySupplierDataSource的新 ObjectDataSource。

将 ProductsBySupplier GridView 绑定到新的 ObjectDataSource

图 16:将 ProductsBySupplier GridView 绑定到 New ObjectDataSource (单击以查看全尺寸图像)

接下来,将 ObjectDataSource 配置为使用 ProductsBLL 类。 由于我们只想检索所选供应商提供的产品,因此指定 ObjectDataSource 应调用 GetProductsBySupplierID(supplierID) 方法来检索其数据。 从“更新”、“插入”和“删除”选项卡的下拉列表中选择“ (无) ”。

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

图 17:将 ObjectDataSource 配置为使用 GetProductsBySupplierID(supplierID) 方法 (单击以查看全尺寸图像)

在“更新”、“插入”和“删除”选项卡中将 Drop-Down Lists 设置为“ (None”)

图 18:在“更新”、“插入”和“删除”选项卡中将 Drop-Down Lists 设置为“ () 无” (单击以查看全尺寸图像)

配置 SELECT、UPDATE、INSERT 和 DELETE 选项卡后,单击“下一步”。 GetProductsBySupplierID(supplierID)由于 该方法需要输入参数,“创建数据源”向导会提示我们指定参数值的源。

此处有几种指定参数值源的选项。 可以使用默认的 Parameter 对象,以编程方式将 属性的值 SuppliersSelectedIndex 分配给 ObjectDataSource 事件处理程序中的 Parameter DefaultValue 属性 Selecting 。 有关以 编程方式将值分配给 ObjectDataSource 参数的复习,请参阅以编程方式设置 ObjectDataSource 的参数值教程。

或者,可以使用 ControlParameter 并引用 Suppliers GridView 属性SelectedValue ( 见图 19) 。 GridView 属性SelectedValue返回与 DataKey 属性对应的SelectedIndex值。 若要使此选项正常工作,我们需要在单击按钮时ListProducts以编程方式将 GridView 属性SelectedIndex设置为所选行。 另一个好处是,通过设置 SelectedIndex,所选记录将采用 SelectedRowStyle 主题 (黄色背景) 中定义的 DataWebControls

使用 ControlParameter 将 GridView s SelectedValue 指定为参数源

图 19:使用 ControlParameter 将 GridView s SelectedValue 指定为参数源 (单击以查看全尺寸图像)

完成向导后,Visual Studio 将自动添加产品数据字段的字段。 删除除 、 CategoryNameUnitPrice BoundFields 之外ProductName的所有属性,并将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>

若要完成此练习,我们需要在单击按钮时将 GridView 的 SelectedIndex 属性SelectedSuppliersIndex设置为 ,ProductsBySupplierPanel将 Panel 属性Visible设置为 trueListProducts 为此,请为 ListProducts Button Web 控件 事件 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 中选择供应商,则会 ChooseSupplierMsg 显示标签并 ProductsBySupplierPanel 隐藏面板。 否则,如果已选择供应商, ProductsBySupplierPanel 则显示 并更新 GridView 属性 SelectedIndex

图 20 显示了选择 Bigfoot Breweries 供应商并单击“在页面上显示产品”按钮后的结果。

大脚啤酒厂提供的产品在同一页面上列出

图 20:Bigfoot Breweries 提供的产品列在同一页上 (单击以查看全尺寸图像)

总结

使用带有 DetailsView 的可选主网格视图教程中所述,可以使用属性设置为 trueShowSelectButton CommandField 从 GridView 中选择记录。 但 CommandField 将其按钮显示为常规按钮、链接或图像。 另一种行选择用户界面是在每个 GridView 行中提供单选按钮或复选框。 在本教程中,我们检查了如何添加单选按钮列。

遗憾的是,添加一列单选按钮并不像预期的那样简单或简单。 没有内置 RadioButtonField 可在单击按钮时添加,在 TemplateField 中使用 RadioButton Web 控件会引入其自身的一组问题。 最后,为了提供这样的接口,我们必须创建自定义 DataControlField 类,或者在事件期间 RowCreated 将相应的 HTML 注入到 TemplateField 中。

在探索了如何添加单选按钮列之后,让我们将注意力转向添加一列复选框。 使用一列复选框,用户可以选择一个或多个 GridView 行,然后对 (的所有选定行执行某些操作,例如从基于 Web 的电子邮件客户端选择一组电子邮件,然后选择删除所有选定的电子邮件) 。 在下一教程中,我们将了解如何添加此类列。

编程愉快!

关于作者

Scott Mitchell 是七本 ASP/ASP.NET 书籍的作者, 4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0自学。 可以在 上联系 mitchell@4GuysFromRolla.com他, 也可以通过他的博客联系到他,该博客可在 http://ScottOnWriting.NET中找到。

特别感谢

本教程系列由许多有用的审阅者查看。 本教程的首席审阅者是 David Suru。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处放置一行 mitchell@4GuysFromRolla.com。