You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

访问GridView单元格ItemTemplate中控件时出现Null引用异常

GridView下拉框Null引用异常及取值问题

问题现象

调试时,以下代码触发Null引用异常:

string disposResult = ((HtmlSelect)row.Cells[1].FindControl("DropDownList1")).Value;

需求是获取GridView中每行下拉框的选中值。

现有代码

GridView定义

<asp:GridView ID="MyGridView" runat="server" AutoGenerateColumns="false">
    <Columns>
        <asp:BoundField DataField="SerialNo" HeaderText="Serial No" />
        <asp:TemplateField HeaderText="Disposition result">                
            <ItemTemplate>                          
                <%# Eval("Disposition result") %>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Disposition comment">
            <ItemTemplate>
                <textarea runat="server" ID="txtDispositionComment" Rows="5" CssClass="form-control" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Note for Group">
            <ItemTemplate>
                <textarea runat="server" ID="txtNoteForGroup" Rows="5" CssClass="form-control" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

数据源生成代码

protected async void serialNoFieldData()
{
    string NMRValue = Request.QueryString["NMRValue"];
    string apiUrl = "https://itapps/nmrapi_V2/api/nmr?NMR_Number=" + NMRValue;
    using (HttpClient client = new HttpClient())
    {
        string apiResponse = await client.GetStringAsync(apiUrl);
        JObject responseData = JObject.Parse(apiResponse);
        JArray data = JArray.Parse(responseData["data"].ToString());

        DataTable dt = new DataTable();
        dt.Columns.Add("SerialNo");
        dt.Columns.Add("Disposition result");
        dt.Columns.Add("Disposition comment");
        dt.Columns.Add("Note for Group");

        // 获取Disposition result列的下拉框选项
        string dropdownApiUrl = "https://itapps/nmrapi_V2/api/DBParameter/NMR_Form?PN=DisposRes";
        string dropdownApiResponse = await client.GetStringAsync(dropdownApiUrl);
        JObject dropdownData = JObject.Parse(dropdownApiResponse);

        List<string> dropdownValues = new List<string>();
        if ((bool)dropdownData["success"])
        {
            JArray dataArray = (JArray)dropdownData["data"];
            foreach (string item in dataArray)
            {
                dropdownValues.Add(item);
            }
        }

        foreach (JObject item in data)
        {
            string serialNumber = (string)item["SerialNo"];

            // 填充表单字段
            // 添加新行到DataTable
            DataRow dr = dt.NewRow();
            dr["SerialNo"] = serialNumber;
            string dropdownHtml = CreateDropDownList(dropdownValues);
            dr["Disposition result"] = dropdownHtml;
            dr["Disposition comment"] = CreateTextArea();
            dr["Note for Group"] = CreateTextArea();
            dt.Rows.Add(dr);
        }

        // 将DataTable绑定到GridView控件
        MyGridView.DataSource = dt;
        MyGridView.DataBind();
    }
}

下拉框HTML生成代码

private string CreateDropDownList(List<string> values)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("<select id='DropDownList1' class='form-control' style='width: 200px;'>");

    foreach (string value in values)
    {
        sb.Append("<option value='" + value + "'>" + value + "</option>");
    }

    sb.Append("</select>");
    return sb.ToString();
}

问题原因

当前实现是将纯HTML字符串直接输出到页面,生成的<select>是客户端控件,没有runat="server"属性,ASP.NET无法将其识别为服务器端控件,因此FindControl("DropDownList1")会返回null,导致Null引用异常。另外,每行的下拉框id都设为DropDownList1,会造成页面元素id重复,不符合HTML规范。

解决方案

方案1:使用服务器端DropDownList控件(推荐)

步骤1:修改GridView的Disposition result列

将原来的ItemTemplate替换为服务器端DropDownList:

<asp:TemplateField HeaderText="Disposition result">                
    <ItemTemplate>                          
        <asp:DropDownList runat="server" ID="DropDownList1" CssClass="form-control" Width="200px"></asp:DropDownList>
    </ItemTemplate>
</asp:TemplateField>

步骤2:存储下拉框选项到全局变量

在页面类中定义全局变量存储下拉选项:

private List<string> _dropdownValues;

然后在serialNoFieldData方法中,获取到dropdownValues后赋值给_dropdownValues:

// 获取Disposition result列的下拉框选项
string dropdownApiUrl = "https://itapps/nmrapi_V2/api/DBParameter/NMR_Form?PN=DisposRes";
string dropdownApiResponse = await client.GetStringAsync(dropdownApiUrl);
JObject dropdownData = JObject.Parse(dropdownApiResponse);

_dropdownValues = new List<string>();
if ((bool)dropdownData["success"])
{
    JArray dataArray = (JArray)dropdownData["data"];
    foreach (string item in dataArray)
    {
        _dropdownValues.Add(item);
    }
}

同时,DataTable中不需要再存下拉框HTML,直接留空即可:

DataRow dr = dt.NewRow();
dr["SerialNo"] = serialNumber;
dr["Disposition result"] = "";
dr["Disposition comment"] = "";
dr["Note for Group"] = "";
dt.Rows.Add(dr);

步骤3:添加GridView的RowDataBound事件绑定下拉框

protected void MyGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        DropDownList ddl = (DropDownList)e.Row.FindControl("DropDownList1");
        ddl.DataSource = _dropdownValues;
        ddl.DataBind();
        // 如需设置默认选中值,可从DataRow中获取
        // string defaultVal = (string)DataBinder.Eval(e.Row.DataItem, "Disposition result");
        // ddl.SelectedValue = defaultVal;
    }
}

记得在GridView标签中添加事件绑定:OnRowDataBound="MyGridView_RowDataBound"

步骤4:正确获取选中值

此时可以正常通过FindControl获取服务器端控件:

foreach (GridViewRow row in MyGridView.Rows)
{
    if (row.RowType == DataControlRowType.DataRow)
    {
        DropDownList ddl = (DropDownList)row.FindControl("DropDownList1");
        string disposResult = ddl.SelectedValue;
        // 后续处理逻辑
    }
}

方案2:使用客户端HTML控件,通过Request.Form取值

如果坚持使用纯HTML下拉框,需要修改生成逻辑,给每个下拉框设置唯一的name属性:

步骤1:修改CreateDropDownList方法,传入SerialNo作为标识

private string CreateDropDownList(List<string> values, string serialNo)
{
    StringBuilder sb = new StringBuilder();
    // 设置唯一的name属性,包含SerialNo
    sb.Append($"<select name='DropDownList_{serialNo}' class='form-control' style='width: 200px;'>");

    foreach (string value in values)
    {
        sb.Append("<option value='" + value + "'>" + value + "</option>");
    }

    sb.Append("</select>");
    return sb.ToString();
}

调用时传入SerialNo:

string dropdownHtml = CreateDropDownList(dropdownValues, serialNumber);

步骤2:后台取值

通过Request.Form根据唯一name获取选中值:

foreach (GridViewRow row in MyGridView.Rows)
{
    if (row.RowType == DataControlRowType.DataRow)
    {
        string serialNo = row.Cells[0].Text;
        string disposResult = Request.Form[$"DropDownList_{serialNo}"];
        // 后续处理逻辑
    }
}

内容的提问来源于stack exchange,提问作者Guru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 01:12:53