简体   繁体   中英

Excel C# Interop - narrow selected range to populated cells only

I have a VSTO solution that corrects data in highlighted cells. The issue I am having is if the user selects an entire row/column, the program cycles through thousands of empty cells, long after the last cell has been processed. 单元很长时间之后,该程序将循环遍历数千个空单元格。

My code looks like this:

        var addIn = Globals.ThisAddIn;
        Excel.Worksheet sheet = addIn.Application.ActiveSheet;
        Excel.Range range = addIn.Application.Selection;

        foreach (Excel.Range cell in range.Cells)
        {
            var val = cell.Value2;
            if (val == null)
                continue;

I've seen threads on how to use:

AdvancedFilter(Excel.XlFilterAction.xlFilterInPlace, Type.Missing)

But I can't seem to tie the two. I either want my "range" object to be limited to only populated cells or to be able to short-circuit my foreach loop when I have supassed the last value.

I thought of doing something like this:

if (cell.Row > populatedRange.Row ||
    cell.Column > populatedRange.Column)
    break;

But this has the potential of breaking the code if something other than an entire row/column is selected (user selects a cell outside of the populated range, and all subsequent populated cells are ignored).

I know I'm missing something simple, but my attempts (and searches) have not yielded the answer.

You can use the Range.SpecialCells method on the sheet to find the last cell. Then you can modify your loop to exit when you move beyond the last row or column. The following snippet will give your the row and column number of the last cell. You may still process some empty cells, but you won't be going all the way down to row 1048574.

Excel.Range last = Globals.Sheet1.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
int lastRowNumber = last.Row;
int lastColumnNumber = last.Column;

Why don't you convert your range range.Cells into an array and deal with this in memory. Its way faster than iterating through each cell and then you can use all memory power of Linq or whatever to filter and correct your data... then you just send back to excel the updated range.

Doing:

var obj = range.Cell

will cast your range into object[,] of 2 dimensions. I think

System.Array myArray = (System.Array)(range.Cells)

would work too.

Regards.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM