如何在Excel表格中获取被占用单元格的范围

35

我使用C#自动化处理Excel文件。我已经获取到了工作簿和其中包含的表格。 如果例如在Sheet1中有两列和5行,我想要获取占用单元格的范围为A1:B5。我尝试了以下代码,但没有得到正确的结果。 列号和行号都很大,并且单元格也为空。

     Excel.Range xlRange = excelWorksheet.UsedRange;
     int col = xlRange.Columns.Count;
     int row = xlRange.Rows.Count;

有没有其他方法可以用来获取那个范围?


1
你在目标范围内有什么样的数据。我以前使用过UsedRange属性,没有任何问题,只要工作簿和工作表是活动状态。 - mas_oz2k1
10个回答

62

我遇到了和你类似的问题。最终有效的方法是:

iTotalColumns = xlWorkSheet.UsedRange.Columns.Count;
iTotalRows = xlWorkSheet.UsedRange.Rows.Count;

//These two lines do the magic.
xlWorkSheet.Columns.ClearFormats();
xlWorkSheet.Rows.ClearFormats();

iTotalColumns = xlWorkSheet.UsedRange.Columns.Count;
iTotalRows = xlWorkSheet.UsedRange.Rows.Count;

依我所见,当您从Excel中删除数据时,它会继续认为这些单元格中有数据,尽管它们是空白的。当我清除格式时,它会移除空白单元格,从而返回实际计数。


3
这是我看到的唯一没有问题的答案。它解决了以下问题:检测空格式单元格,检测隐藏行/列中的值。 - Gerhard Powell
2
xlWorkSheet.Columns.ClearFormats(); xlWorkSheet.Rows.ClearFormats(); 很好的答案。 - VibeeshanRC
3
这是一个非常有用的答案,但请注意,这需要对电子表格具有写入权限。 - H H
4
啊呸,是的,这个方法确实可以解决问题(之前,Excel报告说我有16349列,而不只是13列!)但是,显然地,它会移除所有单元格格式。有没有什么方法可以在不移除格式的情况下获取“真正”的列数呢? - Mike Gledhill
2
好的解决方案。但是我通过艰难的方式发现这个解决方案的缺点是,如果您需要按照Excel中显示的值读取值,则清除所有格式将无法实现。我在解决这个问题时发现了这个:http://stackoverflow.com/questions/39931543/c-sharp-excel-date-value-is-coming-as-numeric-value - AllSolutions
显示剩余2条评论

20
Excel.Range last = sheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range range = sheet.get_Range("A1", last);

"range"现在将成为所占用的单元格范围。


1
它始终返回空单元格时间,我认为问题的作者希望“不要获得”那些空单元格。 - Javidan

4
请查看 Range.SpecialCells 方法。例如,要获取具有常量值或公式的单元格,请使用:
_xlWorksheet.UsedRange.SpecialCells(
        Microsoft.Office.Interop.Excel.XlCellType.xlCellTypeConstants |
        Microsoft.Office.Interop.Excel.XlCellType.xlCellTypeFormulas)

3
经历了六年和两次痛苦的Excel迭代后...这似乎正是我所需要的,但在Excel 2013中,它会抛出一个“Range类的SpecialCells方法失败”的异常...使用"Cells.SpecialCells(XlCellType.xlCellTypeLastCell)"可以工作,但有时会返回一个完全错误的答案(例如包含9列数据的工作表中的第16349列...)。 - Mike Gledhill

4

我唯一能让它在所有情况下(除了受保护的工作表)正常工作的方法(基于Farham的答案):

它支持:

  • 扫描隐藏行/列

  • 忽略没有数据/公式的格式化单元格

代码:

// Unhide All Cells and clear formats
sheet.Columns.ClearFormats();
sheet.Rows.ClearFormats();

// Detect Last used Row - Ignore cells that contains formulas that result in blank values
int lastRowIgnoreFormulas = sheet.Cells.Find(
                "*",
                System.Reflection.Missing.Value,
                InteropExcel.XlFindLookIn.xlValues,
                InteropExcel.XlLookAt.xlWhole,
                InteropExcel.XlSearchOrder.xlByRows,
                InteropExcel.XlSearchDirection.xlPrevious,
                false,
                System.Reflection.Missing.Value,
                System.Reflection.Missing.Value).Row;
// Detect Last Used Column  - Ignore cells that contains formulas that result in blank values
int lastColIgnoreFormulas = sheet.Cells.Find(
                "*",
                System.Reflection.Missing.Value,
                System.Reflection.Missing.Value,
                System.Reflection.Missing.Value,
                InteropExcel.XlSearchOrder.xlByColumns,
                InteropExcel.XlSearchDirection.xlPrevious,
                false,
                System.Reflection.Missing.Value,
                System.Reflection.Missing.Value).Column;

// Detect Last used Row / Column - Including cells that contains formulas that result in blank values
int lastColIncludeFormulas = sheet.UsedRange.Columns.Count;
int lastColIncludeFormulas = sheet.UsedRange.Rows.Count;

1
哇,太棒了。你的代码真是太棒了。你说得对,这是我找到的唯一一个正确获取工作表列/行数的代码。VSTO自带的“SpecialCells(XlCellType.xlCellTypeLastCell)”有时会告诉我我的9列工作表包含16349列数据。使用你的代码,我得到了我想要的9列。太棒了。 - Mike Gledhill
2
仅仅是补充一下,在经过大量测试后,我们发现这段代码似乎无法检测到包含值的Excel单元格,尤其是在已经“分组”和折叠的列/行中。我们的用户也抱怨说它会漏掉只包含公式的列/行,因此我们需要进行两次查找——一次查找“XlFindLookIn.xlValues”,一次查找“XlFindLookIn.xlFormulas”。 - Mike Gledhill
使用ClearFormats的问题在于,如果需要读取单元格文本的确切显示方式,则无法实现。我在其中一个项目中有这样的要求;那么有没有一种方法可以在不使用ClearFormats的情况下找到已使用范围? - AllSolutions
2
非常好的回答,我可以指出你在列代码中写了三次“System.Reflection.Missing.Value”。我已经在我的代码中进行了更正。 - AltF4_

0

这个问题有点老了,但如果有人正在寻找解决方案,这对我有效。

using Excel = Microsoft.Office.Interop.Excel;

Excel.ApplicationClass excel = new Excel.ApplicationClass();
Excel.Application app = excel.Application;
Excel.Range all = app.get_Range("A1:H10", Type.Missing);

7
假设您清楚地知道所需范围,这样做就可行。其他提供的解决方案更为通用且完美地实现了其功能。 - Dan
@Dan:实际上,它们都对我不起作用——总是得到15242行,而应该只有2000多行。 - 537mfb
1
这个方法肯定只会给你10行数据。你的数据是什么样子的?也许可以创建一个新问题,并链接到这个问题,解释你尝试过哪些方法以及结果。 - Dan

0

这是专门用于查找公式的,但您应该能够通过更改测试起始单元格的方式将其扩展到一般内容。您将不得不处理此范围之外的单个单元格范围。

    public static Range GetUsedPartOfRange(this Range range)
    {
        Excel.Range beginCell = range.Cells[1, 1];
        Excel.Range endCell = range.Cells[range.Rows.Count, range.Columns.Count];

        if (!beginCell.HasFormula)
        {
            var beginCellRow = range.Find(
                "*",
                beginCell,
                XlFindLookIn.xlFormulas,
                XlLookAt.xlPart,
                XlSearchOrder.xlByRows,
                XlSearchDirection.xlNext,
                false);

            var beginCellCol = range.Find(
                "*",
                beginCell,
                XlFindLookIn.xlFormulas,
                XlLookAt.xlPart,
                XlSearchOrder.xlByColumns,
                XlSearchDirection.xlNext,
                false);

            if (null == beginCellRow || null == beginCellCol)
                return null;

            beginCell = range.Worksheet.Cells[beginCellRow.Row, beginCellCol.Column];
        }

        if (!endCell.HasFormula)
        {
            var endCellRow = range.Find(
            "*",
            endCell,
            XlFindLookIn.xlFormulas,
            XlLookAt.xlPart,
            XlSearchOrder.xlByRows,         
            XlSearchDirection.xlPrevious,
            false);

            var endCellCol = range.Find(
                "*",
                endCell,
                XlFindLookIn.xlFormulas,
                XlLookAt.xlPart,
                XlSearchOrder.xlByColumns,
                XlSearchDirection.xlPrevious,
                false);

            if (null == endCellRow || null == endCellCol)
                return null;

            endCell = range.Worksheet.Cells[endCellRow.Row, endCellCol.Column];
        }

        if (null == endCell || null == beginCell)
            return null;

        Excel.Range finalRng = range.Worksheet.Range[beginCell, endCell];

        return finalRng;
    }
}

0
dim lastRow as long   'in VBA it's a long 
lastrow = wks.range("A65000").end(xlup).row

1
这个解决方案只适用于VBA,不是C#的解决方案。 - user2140173

0

这两行代码单独使用对我来说不起作用:

xlWorkSheet.Columns.ClearFormats();
xlWorkSheet.Rows.ClearFormats();

您可以通过在工作表中按下Ctrl+End来进行测试,看看选择了哪个单元格。

我发现在前两行后添加这一行可以解决我遇到的所有情况:

Excel.Range xlActiveRange = WorkSheet.UsedRange;

有没有一种编程方法可以找到在使用Ctrl + End时Excel将显示的单元格? - AllSolutions

0
你不应该通过按“删除”键来删除方框中的数据,我认为这是问题的原因,因为Excel仍会将方框检测为 “” <- 仍具有值,您应该通过右键单击该方框并选择“删除”来进行删除。

0
你可以尝试使用currentRegion属性,如果你知道从哪里开始查找范围。这将给出你所使用范围的边界。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接