C#使用NPOI设置Excel下拉选项的三种方法

一颗松果
一颗松果
发布时间:2026-10-16| 6人浏览过
原创

在使用C#生成Excel模板时,通过NPOI库限制单元格输入并添加下拉选择框是常见的数据规范化需求。本文将分别介绍固定值直接指定、引用隐藏工作表区域以及多级联动下拉这三种核心实现方式,包含关键类的使用说明及完整的代码片段。

直接设置下拉值

该方法适用于下拉选项较少且固定的场景,如状态枚举或性别选项。其局限在于传入的字符串数组必须总长度不超过255个字符,超出范围可能引发错误或缺失内容。

第1步:定义下拉验证方法

该步骤的核心是通过 DVConstraint.CreateExplicitListConstraint 明确列出允许的数值,并将约束绑定到指定的单元格行与列范围。若用户输入不符合列表要求,将弹出错误提示。

public static void SetCellDropdownList(ISheet sheet, int firstcol, int lastcol, string[] vals)
{
    // 设置生效的行和列:行从1到65535,列为firstcol到lastcol
    var cellRegions = new CellRangeAddressList(1, 65535, firstcol, lastcol);

    // 创建显式列表约束,vals为允许的值数组
    DVConstraint constraint = DVConstraint.CreateExplicitListConstraint(vals);

    // 绑定约束,设置错误标题和内容,并显示提示框
    HSSFDataValidation dataValidate = new HSSFDataValidation(cellRegions, constraint);
    dataValidate.CreateErrorBox("输入不合法", "请输入或选择下拉列表中的值。");
    dataValidate.ShowPromptBox = true;

    // 将验证规则应用到工作表
    sheet.AddValidationData(dataValidate);
}

第2步:调用并应用

在工作簿中创建Sheet后,直接调用上述方法即可生效。注意需先初始化 HSSFWorkbook 对象。

HSSFWorkbook workbook = new HSSFWorkbook();
ISheet sheet = workbook.CreateSheet("sheet1");
// 示例:设置第一列为“男”、“女”、“保密”的下拉选项
ExcelHelper.SetCellDropdownList(sheet, 1, 1, new List<string>() { "男", "女", "保密" }.ToArray());

通过隐藏Sheet引用单元格设置

当所需选项较多(超过255字)或需要动态维护时,推荐将此方法。原理是在内存中创建一个隐藏的辅助Sheet存放选项,并通过命名区域(Name Range)建立公式引用。

第1步:构建引用Sheet的方法

此方法内部会创建一个新的Sheet存储数组值,并将其隐藏以防干扰用户。随后定义一个命名公式指向这些单元格区域,最后基于该公式生成下拉约束。

public static void SetCellDropdownList(HSSFWorkbook workbook, ISheet sheet, string name, int firstcol, int lastcol, string[] vals, int sheetindex = 1)
{
    // 创建专用的字典Sheet用于存放下拉项
    ISheet sheet2 = workbook.CreateSheet(name);
    // 将该Sheet设为隐藏状态
    workbook.SetSheetHidden(sheetindex, true);

    int index = 0;
    foreach (var item in vals)
    {
        sheet2.CreateRow(index).CreateCell(0).SetCellValue(item);
        index++;
    }

    // 定义命名区域公式:$A$1:$A$索引数
    var rangeName = name + "Range";
    IName range = workbook.CreateName();
    range.RefersToFormula = name + "!$A$1:$A$" + index;
    range.NameName = rangeName;

    // 配置作用区域与公式约束
    CellRangeAddressList regions = new CellRangeAddressList(0, 65535, firstcol, lastcol);
    DVConstraint constraint = DVConstraint.CreateFormulaListConstraint(rangeName);
    HSSFDataValidation dataValidate = new HSSFDataValidation(regions, constraint);
    
    dataValidate.CreateErrorBox("输入不合法", "请输入或选择下拉列表中的值。");
    dataValidate.ShowPromptBox = true;
    sheet.AddValidationData(dataValidate);
}

第2步:调用示例

适用于城市区域等较为复杂的动态数据源。

HSSFWorkbook workbook = new HSSFWorkbook();
ISheet sheet = workbook.CreateSheet("sheet1");
// 获取房源类型列表数据
var roomTypeList = GetRoomTypeNameList();
// 调用时将列表转为数组传入
ExcelHelper.SetCellDropdownList(workbook, sheet, "RoomTypeDictionary", 1, 1, roomTypeList.ToArray());

延伸:省市联动下拉实现

对于具有层级关系的复杂数据(如省-市),可以通过 INDIRECT 函数结合命名区域来实现联动效果。即第二列的值随第一列的选择而动态变化。

第1步:构造联动字典Sheet

在隐藏的字典Sheet中,按层级排版数据:第一列放置省份名称,后续各列依次放置对应省份下的城市名称。利用循环遍历构建数据结构。

private void SetCityCellDropdownList(HSSFWorkbook workbook, ISheet sheet, string dictionaryName, int citycol, int areacol, int sheetIndex)
{
    var citylist = GetCityList();
    ISheet sheet2 = workbook.CreateSheet(dictionaryName);
    workbook.SetSheetHidden(sheetIndex, true);

    #region 填充城市与区域数据
    int rowIndex = 0;
    // 第一列填入所有城市/省份名作为锚点
    foreach (var item in citylist)
    {
        sheet2.CreateRow(rowIndex).CreateCell(0).SetCellValue(item.Name);
        rowIndex++;
    }

    // 填充对应列的区域数据
    int n_rowIndex = 0;
    foreach (var item in citylist)
    {
        int areaIndex = 0;
        foreach (var area in item.AreaList)
        {
            IRow row = sheet2.GetRow(areaIndex);
            if (row == null) row = sheet2.CreateRow(areaIndex);
            row.CreateCell(n_rowIndex + 1).SetCellValue(area.Name);
            areaIndex++;
        }
        n_rowIndex++;
    }
    #endregion

    #region 命名区域定义
    int columnIndex = 1;
    // 命名:第一列数据范围
    IName range_Country = workbook.CreateName();
    range_Country.RefersToFormula = string.Format("{0}!${1}$1:${1}${2}", dictionaryName, GetExcelColumnName(columnIndex), citylist.Count);
    range_Country.NameName = "CityRange"; // 保持命名唯一性,原名为"城市"建议改为英文名避免冲突

    // 依次为每个省份定义对应的区域名称
    foreach (var item in citylist)
    {
        int areacount = item.AreaList.Count;
        columnIndex++;
        IName range_area = workbook.CreateName();
        range_area.RefersToFormula = string.Format("{0}!${1}$1:${1}${2}", dictionaryName, GetExcelColumnName(columnIndex), areacount);
        range_area.NameName = item.Name;
    }
    #endregion

    // 执行绑定(调用下方重载方法)
    // 假设城市列号由citycol给出
    SetCellDropdownListByRange(sheet, 1, 65535, citycol, citycol, "CityRange");

    // 联动逻辑:第二列根据第一列的文本去查找同名命名区域的值
    // 这里需要对行做循环以生成不同行的INDIRECT引用
    for (int r = 1; r < 500; r++)
    {
         // 这里的areacol即为关联的第二列
        string colName = GetExcelColumnName(areacol);
        // INDIRECT 引用的目标应匹配第一列对应的单元格值(即城市名)
        // 注意:此处逻辑在原素材中依赖于INDIRECT(${col}${r+1})即下一列同行,需确保命名区域名称与实际单元格的Value完全一致
        SetCellDropdownListByName(sheet, r, r, areacol, areacol, "INDIRECT($" + colName + "$" + (r) + ")");
    }
}

// 辅助:字母转列名
private string GetExcelColumnName(int columnNumber)
{
    int dividend = columnNumber;
    string columnName = String.Empty;
    int modulo;
    while (dividend > 0)
    {
        modulo = (dividend - 1) % 26;
        columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
        dividend = (int)((dividend - modulo) / 26);
    }
    return columnName;
}

第2步:定义按需调用的辅助方法块

为了配合复杂的公式引用(如INDIRECT),可能需要单独的重载方法。

public static void SetCellDropdownListByName(ISheet sheet, int firstRow, int lastRow, int firstCol, int lastCol, string formulaName)
{
    CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
    DVConstraint constraint = DVConstraint.CreateFormulaListConstraint(formulaName);
    HSSFDataValidation dataValidate = new HSSFDataValidation(regions, constraint);
    dataValidate.CreateErrorBox("输入不合法", "请输入或选择下拉列表中的值。");
    sheet.AddValidationData(dataValidate);
}

总结与建议

以上三种方式覆盖了从小型静态列表到大型动态数据的绝大多数Excel导入模板生成场景。其中第一种最简单但受限;第二种是标准解法;第三种涉及较深的公式处理,需注意命名区域的唯一性与Excel原生函数的语法要求。编写此类工具类时,务必保证生成的Excel文件能在本地预览器中正常响应事件。

以上就是C#使用NPOI设置Excel下拉选项的详细内容,更多关于C# Excel开发技巧的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。