Question

I would like to get the values of a non contiguous, multi area range in excel using C#. I have seen another SO question that says I can do something like this:

obj[,] data = sheet.get_Range("B4:K4,B5:K5").get_Value();

However, when I examine the result I see that I only get the data from the first area: "B4:K4".

Testing further, I found that if I request the data in the following way:

obj[,] data = sheet.get_Range( "B4:K4","B5:K5").get_Value();

I get the data for both areas...

So, my question is, is there a way to programmatically combine area addresses such as "B4:K4,B5:K5" in order to get all of the data to which they refer?

Thanks

Was it helpful?

Solution

The solution I came up with isn't as elegant as I would have liked but it does the trick nonetheless:

public List<List<object>> 
GetNonContiguousRowValue(Excel.Worksheet ws, string noncontiguous_address)
{
    var addresses = noncontiguous_address.Split(','); // e.g. "A1:D1,A4:D4"
    var row_data = new List<List<object>>();

    // Get the value of one row at a time:
    foreach (var addr in addresses)
    {
        object[,] arr = ws.get_Range(addr).Value;
        List<object> row = arr.Cast<object>)
                              .Take(arr.GetLength(dimension:1))
                              .ToList<object>();
        row_data.Add(row);
    }
    return row_data;
}

Hope this helps someone else...

OTHER TIPS

If you are trying to get the data from a range table with hidden rows, another technique is to grab the visible cells, and copy them to a new worksheet. When pasted, they will form a contiguous region and the normal object[,] array can be retrieved.

public object[,] GetNonContiguousVisibleRowsData(Excel.Worksheet sheet, string noncontiguous_address)
{
    // Add a new worksheet
    Excel.Workbook book = (Excel.Workbook)sheet.Parent;
    Excel.Sheets sheets = book.Sheets;
    Excel.Worksheet tempSheet = (Excel.Worksheet)sheets.Add();
    Excel.Range cellA1 = tempSheet.get_Range("A1");

    // Get only the visible cells
    Excel.Range nonContiguousRange = sheet.get_Range(noncontiguous_address);
    Excel.Range visibleSourceRange = nonContiguousRange.SpecialCells(Excel.XlCellType.xlCellTypeVisible);

    // Copying the visible cells will result in a contiguous range in tempSheet
    visibleSourceRange.Copy(cellA1);

    // Get the contiguous range and copy the cell value.
    Excel.Range contiguousRange = tempSheet.UsedRange;
    object[,] data = (object[,])contiguousRange.get_Value(Excel.XlRangeValueDataType.xlRangeValueDefault);

    // Release all COM objects from temp sheet, e.g.:
    // System.Runtime.InteropServices.Marshal.ReleaseComObject(contiguousRange);
    // contiguousRange = null;

    tempSheet.Delete();

    // release all other COM objects

    return data;
}

Another way would be to combine the non-contiguous areas together into a named range, and just reference that named range within your C# code. Here is a way to do this (assign this formula to a named range in the Excel Name Manager):

=CHOOSE({1;2;3},Sheet1!$A$1,Sheet2!$A$3,Sheet3!$A$5)

The downside with this method is that each area can only be 1 row high.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top