如何:在电子表格文档中检索隐藏行或隐藏列的列表

本主题演示如何使用 Open XML SDK 2.0 for Microsoft Office 中的类以编程方式检索 Microsoft Office Excel 2007 或 Microsoft Excel 2010 工作表中隐藏行或列的列表,而无需将文档加载到 Excel 中。本主题包含一个演示此任务的示例 GetHiddenRowsOrCols 方法。

上次修改时间: 2011年11月17日

适用范围: Excel 2010 | Office 2010 | PowerPoint 2010 | Word 2010

本文内容
GetHiddenRowsOrCols 方法
调用 GetHiddenRowsOrCols 方法
代码的工作方式
检索隐藏的行或列的索引值的列表
示例代码

必须安装 Open XML SDK 2.0(该链接可能指向英文页面) 才能使用本主题中的示例代码。必须在项目中明确引用以下程序集:

  • WindowsBase

  • DocumentFormat.OpenXml(由 Open XML SDK 安装)

还必须使用以下 using 指令或 Imports 语句编译本主题中的代码。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
Imports System.IO
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Spreadsheet

GetHiddenRowsOrCols 方法

您可以使用 GetHiddenRowsOrCols 方法检索工作表中隐藏行或列的列表。GetHiddenRowsOrCols 方法接受三个参数,分别指示以下内容:

  • 要检查的文档的名称(字符串)。

  • 要检查的工作表的名称(字符串)。

  • 是检测行 (True) 还是列 (False)(布尔值)。

public static List<uint> GetHiddenRowsOrCols(
  string fileName, string sheetName, bool detectRows)
Public Function GetHiddenRowsOrCols(
  ByVal fileName As String, ByVal sheetName As String,
  ByVal detectRows As Boolean) As List(Of UInteger)

调用 GetHiddenRowsOrCols 方法

如果指定的工作表包含任何隐藏的行或列(行和列的编号从 1 而不是从 0 开始),那么该方法将返回包含隐藏行或列的每个索引的无符号整数的列表。若要调用该方法,请传递所有参数值,如下面的示例代码所示。

const string fileName = @"C:\users\public\documents\RetrieveHiddenRowsCols.xlsx";
List<uint> items = GetHiddenRowsOrCols(fileName, "Sheet1", true);
var sw = new StringWriter();
foreach (var item in items)
    sw.WriteLine(item);
Console.WriteLine(sw.ToString());
Const fileName As String = "C:\Users\Public\Documents\RetrieveHiddenRowsCols.xlsx"
Dim items As List(Of UInteger) =
    GetHiddenRowsOrCols(fileName, "Sheet1", True)
Dim sw As New StringWriter
For Each item In items
    sw.WriteLine(item)
Next
Console.WriteLine(sw.ToString())

代码的工作方式

代码首先创建变量 itemList,该变量将包含返回值。

List<uint> itemList = new List<uint>();
Dim itemList As New List(Of UInteger)

接下来,此代码使用 SpreadsheetDocument.Open 方法打开文档,并指示此文档应打开供只读访问(最后一个 false 参数值)。紧接着,此代码使用文档的 WorkbookPart 属性检索对工作簿部分的引用。

using (SpreadsheetDocument document =
    SpreadsheetDocument.Open(fileName, false))
{
    WorkbookPart wbPart = document.WorkbookPart;
    // Code removed here...
}
Using document As SpreadsheetDocument =
    SpreadsheetDocument.Open(fileName, False)

    Dim wbPart As WorkbookPart = document.WorkbookPart
    ' Code removed here...
End Using

为了查找隐藏行或列,代码必须首先检索对指定工作表的引用(假设知道工作表的名称)。这可不像您想象的那么简单。代码必须浏览工作簿部件的 Workbook 属性的所有工作表类型后代,分析找到的每个工作表的 Name 属性。请注意,这种搜索只是简单地浏览工作簿的关系,并不实际查找工作表部件。它只是查找对 Sheet 对象的引用,该对象包含诸如工作表名称和 Id 属性之类的信息。完成此操作最简单的方法是使用 LINQ 查询。

Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
    Where((s) => s.Name == sheetName).FirstOrDefault();
if (theSheet == null)
{
    throw new ArgumentException("sheetName");
}
Dim theSheet As Sheet = wbPart.Workbook.Descendants(Of Sheet)().
    Where(Function(s) s.Name = sheetName).FirstOrDefault()
If theSheet Is Nothing Then
    Throw New ArgumentException("sheetName")

FirstOrDefault 方法返回第一个匹配的引用(在此示例中为工作表)或者一个空引用(如果未找到匹配项)。代码将检查空引用,如果您传递的工作表名称无效,代码将引发异常。现在,您已具有有关工作表的信息,代码必须检索对相应工作表部件的引用。您已检索的工作表信息提供一个 Id 属性,有了该 Id 属性,代码便可以通过调用 WorkbookPart 对象的 GetPartById 方法检索对相应 WorksheetPart 属性的引用。

else
{
    // The sheet does exist.
    WorksheetPart wsPart =
        (WorksheetPart)(wbPart.GetPartById(theSheet.Id));
    Worksheet ws = wsPart.Worksheet;
    // Code removed here...
}
Else
    ' The sheet does exist.
    Dim wsPart As WorksheetPart =
        CType(wbPart.GetPartById(theSheet.Id), WorksheetPart)
    Dim ws As Worksheet = wsPart.Worksheet
    ' Code removed here...
End If

检索隐藏的行或列的索引值的列表

代码使用您在调用方法以确定是检索有关行还是列的信息时指定的 detectRows 参数。

if (detectRows)
{
    // Retrieve hidden rows.
    // Code removed here...
}
else
{
    // Retrieve hidden columns.
    // Code removed here...
}
If detectRows Then
    ' Retrieve hidden rows.
    ' Code removed here...
Else
    ' Retrieve hidden columns.
    ' Code removed here...
End If

检索隐藏行列表的代码实际上只需要一行。

itemList = ws.Descendants<Row>().
    Where((r) => r.Hidden != null && r.Hidden.Value).
    Select(r => r.RowIndex.Value).ToList<uint>();
itemList = ws.Descendants(Of Row).
    Where(Function(r) r.Hidden IsNot Nothing AndAlso
          r.Hidden.Value).
    Select(Function(r) r.RowIndex.Value).ToList()

但是这一行代码会完成很多任务,它首先调用工作表的 Descendants 方法,检索所有行的列表。Where 方法将结果限制为那些其项目的 Hidden 属性不为空且 Hidden 属性的值为 True 的行。Select 方法投影每行的返回值,并返回 RowIndex 属性的值。最后,ToList<TSource> 方法将生成的 IEnumerable<T> 接口转换为无符号整数的 List<T> 对象。如果不存在隐藏的行,则返回的列表将为空。

检索隐藏列的列表则有些复杂,因为 Excel 将多组隐藏列折叠成一个元素,并提供描述该组中第一列和最后一列的 MinMax 属性。因此,检索隐藏列的列表的代码的开始部分与检索隐藏行的代码相同。不过,它必须循环访问索引值(循环访问隐藏列集合中的每个项目,添加介于 Min 和 Max 值之间(含这两个值)的每个索引)。

var cols = ws.Descendants<Column>().
  Where((c) => c.Hidden != null && c.Hidden.Value);
foreach (Column item in cols)
{
    for (uint i = item.Min.Value; i <= item.Max.Value; i++)
    {
        itemList.Add(i);
    }
}
Dim cols = ws.Descendants(Of Column).
  Where(Function(c) c.Hidden IsNot Nothing AndAlso
          c.Hidden.Value)
For Each item As Column In cols
    For i As UInteger = item.Min.Value To item.Max.Value
        itemList.Add(i)
    Next
Next

示例代码

下面是 C# 和 Visual Basic 中的完整 GetHiddenRowsOrCols 示例代码。

public static List<uint> GetHiddenRowsOrCols(
  string fileName, string sheetName, bool detectRows)
{
    // Given a workbook and a worksheet name, return 
    // either a list of hidden row numbers, or a list 
    // of hidden column numbers. If detectRows is true, return
    // hidden rows. If detectRows is false, return hidden columns. 
    // Rows and columns are numbered starting with 1.

    List<uint> itemList = new List<uint>();

    using (SpreadsheetDocument document =
        SpreadsheetDocument.Open(fileName, false))
    {
        WorkbookPart wbPart = document.WorkbookPart;

        Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
            Where((s) => s.Name == sheetName).FirstOrDefault();
        if (theSheet == null)
        {
            throw new ArgumentException("sheetName");
        }
        else
        {
            // The sheet does exist.
            WorksheetPart wsPart =
                (WorksheetPart)(wbPart.GetPartById(theSheet.Id));
            Worksheet ws = wsPart.Worksheet;

            if (detectRows)
            {
                // Retrieve hidden rows.
                itemList = ws.Descendants<Row>().
                    Where((r) => r.Hidden != null && r.Hidden.Value).
                    Select(r => r.RowIndex.Value).ToList<uint>();
            }
            else
            {
                // Retrieve hidden columns.
                var cols = ws.Descendants<Column>().
                    Where((c) => c.Hidden != null && c.Hidden.Value);
                foreach (Column item in cols)
                {
                    for (uint i = item.Min.Value; i <= item.Max.Value; i++)
                    {
                        itemList.Add(i);
                    }
                }
            }
        }
    }
    return itemList;
}
Public Function GetHiddenRowsOrCols(
  ByVal fileName As String, ByVal sheetName As String,
  ByVal detectRows As Boolean) As List(Of UInteger)

    ' Given a workbook and a worksheet name, return either 
    ' a list of hidden row numbers, or a list of hidden 
    ' column numbers. If detectRows is True, return
    ' hidden rows. If detectRows is False, return hidden columns. 
    ' Rows and columns are numbered starting with 1.

    Dim itemList As New List(Of UInteger)

    Using document As SpreadsheetDocument =
        SpreadsheetDocument.Open(fileName, False)

        Dim wbPart As WorkbookPart = document.WorkbookPart

        Dim theSheet As Sheet = wbPart.Workbook.Descendants(Of Sheet)().
            Where(Function(s) s.Name = sheetName).FirstOrDefault()
        If theSheet Is Nothing Then
            Throw New ArgumentException("sheetName")
        Else
            ' The sheet does exist.
            Dim wsPart As WorksheetPart =
                CType(wbPart.GetPartById(theSheet.Id), WorksheetPart)
            Dim ws As Worksheet = wsPart.Worksheet

            If detectRows Then
                ' Retrieve hidden rows.
                itemList = ws.Descendants(Of Row).
                    Where(Function(r) r.Hidden IsNot Nothing AndAlso
                          r.Hidden.Value).
                    Select(Function(r) r.RowIndex.Value).ToList()
            Else
                ' Retrieve hidden columns.
                Dim cols = ws.Descendants(Of Column).
                    Where(Function(c) c.Hidden IsNot Nothing AndAlso
                          c.Hidden.Value)
                For Each item As Column In cols
                    For i As UInteger = item.Min.Value To item.Max.Value
                        itemList.Add(i)
                    Next
                Next
            End If
        End If
    End Using
    Return itemList
End Function

请参阅

引用

Class Library Reference

其他资源

使用 Open XML SDK 2.0 检索 Excel 2010 工作簿中隐藏的行或列的列表