获取非连续范围的值数组

时间:2015-05-20 20:31:29

标签: c# excel vsto

我希望能够为工作表上的可见单元格获取一系列值。但是,Range.Value2属性似乎只适用于连续的单元格。

将可见单元格值转换为多维数组的有效方法是什么?也许我们可以对Range.Areas进行某种循环?

如果您查看下面的示例代码,您会看到.Value2属性仅返回Area中第一个Range的值。

示例输出是(您将看到最后两行缺少可见值):

All Values:

String1     String2     String3     String4     String5
String6     String7     String8     String9     String10
String11    String12    String13    String14    String15
String16    String17    String18    String19    String20
String21    String22    String23    String24    String25


Visible Values:

String1 String2 String3 String4
String6 String7 String8 String9

_

    public static void RunTest()
    {
        SetData();
        HideRowsAndColumns();

        Excel.Application excelApp = Globals.ThisAddIn.Application;
        Excel.Worksheet sht = excelApp.ActiveSheet;
        var usedRange = sht.UsedRange;
        var visibleUsedRange = usedRange.SpecialCells(XlCellType.xlCellTypeVisible);
        var usedRangeVals = (object[,])usedRange.Value2;
        var visibleUsedRangeVals = (object[,]) visibleUsedRange.Value2; //this doesn't get the full set of values because Value2 does not work with non-contiguous ranges

        string s = "All Values:\n\n" + ArrayToString(usedRangeVals) + "\n\nVisible Values:\n\n" +
                        ArrayToString(visibleUsedRangeVals);


        MessageBox.Show(s);
    }

    private static string ArrayToString(object[,] vals)
    {

        int dim1Start = vals.GetLowerBound(0); //Excel Interop will return index-1 based arrays instead of index-0 based
        int dim1End = vals.GetUpperBound(0);
        int dim2Start = vals.GetLowerBound(1);
        int dim2End = vals.GetUpperBound(1);

        var sb = new StringBuilder();
        for (int i = dim1Start; i <= dim1End; i++)
        {
            for (int j = dim2Start; j <= dim2End; j++)
            {
                sb.Append(vals[i, j]);
                if (j != dim2End)
                    sb.Append("\t");
            }
            sb.Append("\n");
        }
        return sb.ToString();
    }

    private static void SetData()
    {
        const int rows = 5;
        const int cols = 5;
        var a = new string[rows, cols];
        for (int i = 0; i < rows; i++)
            for (int j = 0; j < cols; j++)
                a[i, j] = "String" + (i * cols + j + 1);

        Excel.Application excelApp = Globals.ThisAddIn.Application;
        Excel.Worksheet sht = excelApp.ActiveSheet;
        Excel.Range rng = sht.Range[sht.Cells[1, 1], sht.Cells[rows, cols]];
        rng.Value2 = a;
    }

    private static void HideRowsAndColumns()
    {
        Excel.Application excelApp = Globals.ThisAddIn.Application;
        Excel.Worksheet sht = excelApp.ActiveSheet;
        var row = (Excel.Range) sht.Rows[3];
        row.Hidden = true;

        var col = (Excel.Range) sht.Columns[5];
        col.Hidden = true;
    }

1 个答案:

答案 0 :(得分:1)

由于您不想使用上面提到的链接中提到的任何方法,并且您也不想将数据复制到新工作表,这是我能想到的唯一方法。

<强>逻辑

  1. 以只读方式打开工作簿。如果您正在处理具有隐藏行/列的活动工作表,则create a copy(隐藏了这些行/列的excel文件,然后使用该副本。
  2. 查找工作表上的最后一行/列
  3. 遍历工作表的行/列并删除不可见的行/列
  4. 你现在离开了一个连续的范围。复制数组
  5. 关闭Excel文件而不保存。
  6. 注意:我向您展示了循环遍历行的一个示例。你可以为列做类似的事情

    <强>代码

    int _lastRow = xlWorkSheet.Cells[xlWorkSheet.Rows.Count, 1].End[Microsoft.Office.Interop.Excel.XlDirection.xlUp].Row;
    
    for (int i = 1; i <= _lastRow; i++)
    {
        if (xlWorkSheet.Cells[i, 1].Entirerow.Hidden == true)
        xlWorkSheet.Cells[i, 1].EntireRow.Delete(Microsoft.Office.Interop.Excel.XlDirection.xlUp); ;
    }
    

    修改

    我将此添加为单独的部分,而不是删除上述代码,因为它可能会对将来的访问者有所帮助。

    显然,OP可以将可见单元格复制到新工作表,然后使用.Value2将数据存储到数组中,如评论中所示。

    object misValue = System.Reflection.Missing.Value;
    xlNewWorkSheet = xlexcel.Worksheets.Add(misValue, misValue, misValue, misValue);
    
    Excel.Range MyRange = 
    xlWorkSheet.UsedRange.SpecialCells(Excel.XlCellType.xlCellTypeVisible,misValue);
    
    MyRange.Copy(xlNewWorkSheet.get_Range("A1", "A1"));