7

Possible Duplicate:
How to get the range of occupied cells in excel sheet

Im trying to find the last used row in an Excel worksheet. For doing this, I'm using this code:

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

Most of the time it works fine, but sometimes Excel thinks that there's more rows in the sheet than theres suppose to be.

Fx: If I copy data from sheet1, containing 12 rows, to an empty sheet2, then deleting all data in sheet2, by right clicking and press "Delete..." and copy data from sheet3, containing 5 rows, to sheet2, then lastUsedRow will give me the value of 12 which should have been 5.

enter image description here The image example above is suppose to give my the value of 22 as row count, but instead i'll get 634. Notice the scroll bar to the right.

It seems like Excel thinks that some cells are filled even though I just deleted all cells, before copying new data with fewer rows into the sheet.

Are there any way to "resize" the view of the data in the sheet, so that i'll get the right number of used cells or maybe another way to find the number of the last used row?

Thanks.

Community
  • 1
  • 1
Harving
  • 83
  • 1
  • 1
  • 6

3 Answers3

12

Edit: New Solution

Since Joe provided the correct code to get the last used row.

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

And using the following command to clear content and formattings

Selection.Delete
Selection.ClearFormats

This should work ;)

lorenz albert
  • 1,385
  • 2
  • 11
  • 27
  • 1
    I tried all of them and ActiveSheet.UsedRange.Rows.Count almost gave me the right number. It was suppose to give me 22, but gave me 34 for some weird reason. The other two gave me the same value as i'm getting when i use my own line of code, which is about 634. I'll try to see if I can find a more precise example. Maybe that'll help both of us :) – Harving Sep 05 '12 at 08:56
  • Ok go ahead I try to help if I can :P – lorenz albert Sep 05 '12 at 08:59
  • Well, bacause I'm a new user, I'm not allowed to post images yet. But I need 4 more in reputation and I can edit my post with an image example which explain the problem quite good in my opinion. I'll get back to you :) – Harving Sep 05 '12 at 09:14
  • It's now updated with an image example :) – Harving Sep 05 '12 at 09:19
  • I cant use the delete function, becuase that will erase some data that I need. The same goes for formatting, because then i will lose some coloring that is used in some of the rows for some other function. I guess I'll need to do some thinking and maybe solve my problem another way. But know I know what went wrong in the first place :) Thanks for your help! – Harving Sep 05 '12 at 09:51
  • thanks alot,,, in turkish = "Eyvallah adamın dibisin :)))" – Mahmut EFE Jan 25 '13 at 09:36
5

To get the last used row in a worksheet, you can use:

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

Note that:

  • UsedRange does not necessarily start on the first row - the first row might be empty.

  • UsedRange includes cells that contain formatting even if their content is empty. I suspect this is why you're seeing values bigger than you expect. You need to delete formatting as well as data from the empty cells.

I'm not sure how to do the deletion of formatting on cells programmatically

You can use Range.ClearFormats to clear formatting, or Range.Clear to clear everything. In general, if you're not sure how to do something programatically in Excel, try recording a macro, doing it manually, then inspecting the generated macro.

Joe
  • 122,218
  • 32
  • 205
  • 338
  • Yes, you might be right about the formatting! Then a new problem appears, because then I'm not sure how to do the deletion of formatting on cells programmatically. I'll get back to you! :) – Harving Sep 05 '12 at 09:17
  • It is the formatting, and because of that I might need to solve my problem with another solution. But now I know where the problem is. Thanks a lot :) – Harving Sep 05 '12 at 09:52
  • This is a one liner solution that worked for me. Thank you, +1 – Si8 Jan 12 '17 at 14:13
4

Here is the code I use:

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;
    }
}

Note: you might be tempted to replace all the individual cell value checks with CountA but that will fail in certain cases. For example, if a cell contains the formula =IF(A1=55,"Y",""), a resulting empty string will count as a non-blank cell using CountA.

CtrlDot
  • 3,102
  • 3
  • 25
  • 32
  • That works perfectly! If I just modify the code to return rowMax as Integer, then I got what I need :) – Harving Sep 05 '12 at 11:02