Найдите последнюю использованную строку в Excel с помощью C #

Возможный дубликат:
Как получить диапазон занятых ячеек в листе Excel

Я пытаюсь найти последнюю использованную строку на листе Excel. Для этого я использую этот код:

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

В большинстве случаев это работает нормально, но иногда Excel думает, что на листе больше строк, чем предполагалось.

Fx: если я копирую данные из листа 1, содержащего 12 строк, на пустой лист 2, затем удаляю все данные из листа 2, щелкнув правой кнопкой мыши и нажав «Удалить ...» и скопировав данные из листа 3, содержащего 5 строк, в лист 2, затем lastUsedRow даст мне значение 12, которое должно было быть 5.

введите описание изображения здесьПредполагается, что в приведенном выше примере изображения мне присвоено значение 22 в качестве количества строк, но вместо этого я будет 634. Обратите внимание на полосу прокрутки справа.

Кажется, что Excel считает, что некоторые ячейки заполнены, хотя я просто удалил все ячейки, прежде чем копировать новые данные с меньшим количеством строк в лист.

Есть ли способ «изменить размер» представления данных на листе, чтобы получить нужное количество использованных ячеек или, может быть, другой способ найти номер последней использованной строки?

Спасибо.


person Harving    schedule 05.09.2012    source источник
comment
Как вы копируете данные и выбираете ли диапазон, который удаляете вручную?   -  person lorenz albert    schedule 05.09.2012
comment
Я копирую и удаляю данные вручную, чтобы смоделировать различные варианты внешнего вида листов при тестировании своей программы.   -  person Harving    schedule 05.09.2012


Ответы (3)


Вот код, который я использую:

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.

person CtrlDot    schedule 05.09.2012
comment
Это прекрасно работает! Если я просто изменю код, чтобы вернуть rowMax как Integer, то я получил то, что мне нужно :) - person Harving; 05.09.2012

Изменить: новое решение

Поскольку Джо предоставил правильный код для получения последней использованной строки.

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

И используя следующую команду для очистки содержимого и форматирования

Selection.Delete
Selection.ClearFormats

Это должно работать;)

person lorenz albert    schedule 05.09.2012
comment
Я перепробовал их все, и ActiveSheet.UsedRange.Rows.Count почти дал мне правильный номер. Предполагалось, что мне дадут 22, но по какой-то странной причине мне дали 34. Два других дали мне то же значение, которое я получаю, когда использую свою собственную строку кода, а это около 634. Я постараюсь найти более точный пример. Может быть, это поможет нам обоим :) - person Harving; 05.09.2012
comment
Хорошо, продолжай, я стараюсь помочь, если могу: P - person lorenz albert; 05.09.2012
comment
Так как я новый пользователь, мне пока не разрешено публиковать изображения. Но мне нужно еще 4 в репутации, и я могу отредактировать свой пост с примером изображения, которое, на мой взгляд, неплохо объясняет проблему. Я вернусь к вам :) - person Harving; 05.09.2012
comment
Теперь он обновлен примером изображения :) - person Harving; 05.09.2012
comment
Я не могу использовать функцию удаления, потому что она стирает некоторые данные, которые мне нужны. То же самое и с форматированием, потому что тогда я потеряю некоторую окраску, которая используется в некоторых строках для какой-то другой функции. Думаю, мне нужно немного подумать и, возможно, решить мою проблему другим способом. Но я знаю, что в первую очередь пошло не так :) Спасибо за вашу помощь! - person Harving; 05.09.2012
comment
спасибо большое ,,, на турецком = Eyvallah adamın dibisin :))) - person Mahmut EFE; 25.01.2013

Чтобы получить последнюю использованную строку на листе, вы можете использовать:

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

Обратите внимание, что:

  • UsedRange не обязательно начинается с первой строки - первая строка может быть пустой.

  • UsedRange включает ячейки, содержащие форматирование, даже если их содержимое пусто. Я подозреваю, что именно поэтому вы видите ценности больше, чем вы ожидаете. Вам нужно удалить форматирование, а также данные из пустых ячеек.

Не уверен, как программно удалить форматирование ячеек

Вы можете использовать Range.ClearFormats, чтобы очистить форматирование, или Range.Clear, чтобы очистить все. В общем, если вы не знаете, как делать что-то в Excel программно, попробуйте записать макрос, сделать это вручную, а затем проверить сгенерированный макрос.

person Joe    schedule 05.09.2012
comment
Да, возможно, вы правы насчет форматирования! Затем появляется новая проблема, потому что тогда я не уверен, как программно удалить форматирование ячеек. Я вернусь к вам! :) - person Harving; 05.09.2012
comment
Это форматирование, и из-за этого мне может потребоваться решить мою проблему другим решением. Но теперь я знаю, в чем проблема. Большое спасибо :) - person Harving; 05.09.2012
comment
Это однострочное решение, которое сработало для меня. Спасибо, +1 - person Si8; 12.01.2017