如何用C#实现Excel工作簿及DataGridView数据的全局模糊搜索?
解决DataGridView全局模糊搜索与Excel工作簿直接搜索问题
一、修复DataGridView全局模糊搜索的空引用错误
你碰到的Object reference not set to an instance of an object错误,大概率是这几个原因导致的:
- 没保存原始数据源(比如导入后的DataTable),直接操作DataGridView导致数据源丢失
- 遍历列时遇到空值单元格,没做空值处理引发空引用
- 绑定的数据源不是DataTable,转换过程中出现空引用
正确实现步骤:
- 首先在类级别保存原始的DataTable(导入Excel后存好,别直接用DataGridView的数据源):
private DataTable _originalDataTable; // 全局变量保存原始导入数据
- Excel导入完成后,把数据赋值给这个变量并绑定到DataGridView:
// 假设你已经完成Excel导入得到dataTable _originalDataTable = dataTable.Copy(); // 深拷贝避免修改原始数据 dataGridView1.DataSource = _originalDataTable;
- 在TextBox的TextChanged事件里实现全局模糊搜索:
private void txtSearch_TextChanged(object sender, EventArgs e) { // 先判断原始数据源是否存在,直接避免空引用 if (_originalDataTable == null) return; string searchText = txtSearch.Text.Trim().ToLower(); // 搜索框为空时,直接恢复原始数据 if (string.IsNullOrEmpty(searchText)) { dataGridView1.DataSource = _originalDataTable; return; } // 创建和原始表结构一致的过滤表 DataTable filteredTable = _originalDataTable.Clone(); foreach (DataRow row in _originalDataTable.Rows) { bool isMatch = false; // 遍历当前行的所有列,检查是否有匹配内容 foreach (DataColumn col in _originalDataTable.Columns) { // 处理单元格空值,用?.和??运算符避免空引用 string cellValue = row[col]?.ToString()?.ToLower() ?? string.Empty; if (cellValue.Contains(searchText)) { isMatch = true; break; // 只要有一列匹配,就标记该行符合条件 } } if (isMatch) { filteredTable.ImportRow(row); // 把匹配的行导入过滤表 } } // 绑定过滤后的表到DataGridView dataGridView1.DataSource = filteredTable; }
关键注意点:
- 必须保存原始数据源,不能直接修改DataGridView的Rows集合,否则会丢失原始数据
- 一定要处理单元格空值,避免空引用异常
- 统一转成小写(或大写)做匹配,实现不区分大小写的全局搜索
二、C#直接在Excel工作簿中执行全局模糊搜索
如果想直接在Excel文件里搜索(不用先导入DataGridView),推荐两种常用方案:Microsoft.Office.Interop.Excel(依赖本地Excel)或EPPlus(轻量无依赖)。
方法1:使用Microsoft.Office.Interop.Excel
先安装NuGet包Microsoft.Office.Interop.Excel,然后遍历所有工作表、行、列:
using Microsoft.Office.Interop.Excel; public List<string> SearchExcelFile(string excelPath, string searchText) { List<string> matchResults = new List<string>(); Application excelApp = new Application(); Workbook workbook = null; try { workbook = excelApp.Workbooks.Open(excelPath); string lowerSearch = searchText.ToLower(); foreach (Worksheet worksheet in workbook.Worksheets) { Range usedRange = worksheet.UsedRange; // 遍历所有已使用的单元格 for (int row = 1; row <= usedRange.Rows.Count; row++) { for (int col = 1; col <= usedRange.Columns.Count; col++) { string cellValue = usedRange.Cells[row, col]?.Value?.ToString()?.ToLower() ?? string.Empty; if (cellValue.Contains(lowerSearch)) { // 记录匹配的位置和内容 matchResults.Add($"工作表:{worksheet.Name},行{row}列{col},内容:{usedRange.Cells[row, col].Value}"); } } } } } catch (Exception ex) { Console.WriteLine($"搜索出错:{ex.Message}"); } finally { workbook?.Close(false); excelApp.Quit(); // 释放COM对象,避免内存泄漏 System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp); } return matchResults; }
方法2:使用EPPlus(推荐,无需安装Excel)
安装NuGet包EPPlus(注意EPPlus 5+需要商业许可,非商用可以用4.x版本):
using OfficeOpenXml; public List<string> SearchExcelWithEPPlus(string excelPath, string searchText) { List<string> matchResults = new List<string>(); string lowerSearch = searchText.ToLower(); // 设置非商用许可证 ExcelPackage.LicenseContext = LicenseContext.NonCommercial; using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath))) { foreach (ExcelWorksheet worksheet in package.Workbook.Worksheets) { // 获取实际使用的单元格范围 int rowCount = worksheet.Dimension?.Rows ?? 0; int colCount = worksheet.Dimension?.Columns ?? 0; for (int row = 1; row <= rowCount; row++) { for (int col = 1; col <= colCount; col++) { string cellValue = worksheet.Cells[row, col].Text?.ToLower() ?? string.Empty; if (cellValue.Contains(lowerSearch)) { matchResults.Add($"工作表:{worksheet.Name},行{row}列{col},内容:{worksheet.Cells[row, col].Text}"); } } } } } return matchResults; }
注意事项:
- Interop方式需要目标机器安装Excel,且务必释放COM对象避免内存泄漏
- EPPlus更轻量,适合服务器或无Excel环境,注意许可证合规性
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

