使用C#在Excel中查找上次使用的行

时间:2012-09-05 07:43:17

标签: c# add-in worksheet excel

  

可能重复:
  How to get the range of occupied cells in excel sheet

我试图在Excel工作表中找到最后使用的行。为此,我正在使用此代码:

int lastUsedRow = currentWS.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell,Type.Missing).Row;

大部分时间它工作正常,但有时候Excel认为表格中的行数比假设的要多。

Fx:如果我将包含12行的sheet1中的数据复制到空的sheet2,然后删除sheet2中的所有数据,通过右键单击并按“删除...”并从包含5行的sheet3复制数据到sheet2,那么lastUsedRow会给我12的值,应该是5。

enter image description here 上面的图像示例假设我将值22作为行计数,但我会得到634.请注意右侧的滚动条。

似乎Excel认为即使我刚刚删除了所有单元格,但在将具有较少行的新数据复制到工作表中之前,某些单元格仍然已填充。

有没有办法“调整”工作表中数据的视图,这样我就可以获得正确数量的已用过的单元格,或者找到最后一次使用行数的另一种方式?

感谢。

3 个答案:

答案 0 :(得分:12)

编辑:新解决方案

由于Joe提供了正确的代码来获取最后一次使用的行。

Worksheet.UsedRange.Row + Worksheet.UsedRange.Rows.Count - 1 

使用以下命令清除内容和格式

Selection.Delete
Selection.ClearFormats

这应该有用;)

答案 1 :(得分:5)

要获取工作表中最后使用的行,您可以使用:

Worksheet.UsedRange.Row + Worksheet.UsedRange.Rows.Count - 1

请注意:

  • UsedRange不一定从第一行开始 - 第一行可能为空。

  • UsedRange包含包含格式的单元格,即使其内容为空。我怀疑这就是为什么你看到的价值超出你的预期。您需要删除格式以及空单元格中的数据。

  

我不确定如何以编程方式删除单元格上的格式

您可以使用Range.ClearFormats清除格式,或Range.Clear清除所有内容。通常,如果您不确定如何在Excel中以编程方式执行某些操作,请尝试录制宏,手动执行,然后检查生成的宏。

答案 2 :(得分:4)

以下是我使用的代码:

public static string GetMinimalUsedRangeAddress(Excel.Worksheet sheet)
{
    string address = String.Empty;
    try
    {
        int rowMax = 0;
        int colMax = 0;

        Excel.Range usedRange = sheet.UsedRange;
        Excel.Range lastCell = usedRange.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
        int lastRow = lastCell.Row;
        int lastCol = lastCell.Column;
        int rowMin = lastRow + 1;
        int colMin = lastCol + 1;

        int rr = usedRange.Rows.Count;
        int cc = usedRange.Columns.Count;
        for (int r = 1; r <= rr; r++)
        {
            for (int c = 1; c <= cc; c++)
            {
                Excel.Range cell = usedRange.Cells[r, c] as Excel.Range;
                if (cell != null && cell.Value != null && !String.IsNullOrEmpty(cell.Value.ToString()))
                {
                    if (cell.Row > rowMax)
                        rowMax = cell.Row;
                    if (cell.Column > colMax)
                        colMax = cell.Column;
                    if (cell.Row < rowMin)
                        rowMin = cell.Row;
                    if (cell.Column < colMin)
                        colMin = cell.Column;
                }
                MRCO(cell);
            }
        }

        if (!(rowMax == 0 || colMax == 0 || rowMin == lastRow + 1 || colMin == lastCol + 1))
            address = Cells2Address(rowMin, colMin, rowMax, colMax);

        MRCO(lastCell);
        MRCO(usedRange);
    }
    catch (Exception ex)
    {
        // log as needed
    }
    return address; // caller should test return for String.Empty
}


public static string Cells2Address(int row1, int col1, int row2, int col2)
{
    return ColNum2Letter(col1) + row1.ToString() + ":" + ColNum2Letter(col2) + row2.ToString();
}


public static string ColNum2Letter(int colNum)
{
    if (colNum <= 26) 
        return ((char)(colNum + 64)).ToString();

    colNum--; //decrement to put value on zero based index
    return ColNum2Letter(colNum / 26) + ColNum2Letter((colNum % 26) + 1);
}


public static void MRCO(object obj)
{
    if (obj == null) { return; }
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
    }
    catch
    {
        // ignore, cf: http://support.microsoft.com/default.aspx/kb/317109
    }
    finally
    {
        obj = null;
    }
}

注意:您可能想要用CountA替换所有单个单元格值检查,但在某些情况下会失败。例如,如果单元格包含公式=IF(A1=55,"Y",""),则生成的空字符串将使用CountA计为非空单元格。