C# 在VSTO Excel中,如何检测单元格中的数据?

C# 在VSTO Excel中,如何检测单元格中的数据?,c#,.net,excel,vsto,office-2007,C#,.net,Excel,Vsto,Office 2007,一种快速检测给定工作表中是否有数据的过程,无需实际遍历工作表的所有行/列 对于我当前的流程,我当前正在遍历整个工作表,并且在导入过程中有一些明显的延迟时间。这应该非常快: private void CheckForContent() { Worksheet activeSheet = ActiveSheet; var range = activeSheet.get_Range("A1", GetExcelColumnName(activeSheet

一种快速检测给定工作表中是否有数据的过程,无需实际遍历工作表的所有行/列


对于我当前的流程,我当前正在遍历整个工作表,并且在导入过程中有一些明显的延迟时间。

这应该非常快:

    private void CheckForContent()
    {
        Worksheet activeSheet = ActiveSheet;
        var range = activeSheet.get_Range("A1", GetExcelColumnName(activeSheet.Columns.Count)+activeSheet.Rows.Count.ToString() );
        range.Select();
        range.Copy();
        string text = Clipboard.GetText().Trim();
        if(string.IsNullOrEmpty(text))
        {
            MessageBox.Show("No text");
        }
    }

    private string GetExcelColumnName(int columnNumber)
    {
        int dividend = columnNumber;
        string columnName = String.Empty;
        int modulo;

        while (dividend > 0)
        {
            modulo = (dividend - 1) % 26;
            columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
            dividend = (int)((dividend - modulo) / 26);
        }
        return columnName;
    }

为了避免循环并利用近乎瞬时的执行速度,可以使用
Excel.WorksheetFunction.CountA
方法,该方法返回与=CountA()工作表函数相同的结果

假设您的Excel.Application引用名为“excelApp”,您的Excel.Worksheet引用名为“工作表”,您可以在C#4.0中使用如下代码:

在C#3.0及以下版本中,它更为详细,因为您必须显式提供缺少的可选参数:

// C# 3.0 and below
int dataCount = (int)excelApp.WorksheetFunction.CountA(
    worksheet.Cells, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

if (dataCount == 0)
{
    // All cells on the worksheet are empty.
}
else
{
    // There is at least one cell on the worksheet that has non-empty contents.
}

我找到了下面的解决方案,它也是瞬时的,但我不确定它有多精确。。。到目前为止,它已经通过了我所有的测试

这是给任何想知道的人的:

Worksheet sheet = (Worksheet)this.Application.ActiveSheet;
Range usedRange = sheet.UsedRange;
bool isUsed = (usedRange.Count > 1);
if (usedRange.Count == 1)
{
  isUsed = (usedRange.Value2 != null) &&
           (!string.IsNullOrEmpty(usedRange.Value2.ToString()));
}

if(isUsed)
{
  // worksheet cells not empty
}

我想这比每次检查或计算工作表中的所有非空单元格时打开剪贴板要简单得多。感谢Mikael和Mike,我感谢你们的回答。

我与VSTO和Excel一起工作了一段时间,工作非常紧张,所以我希望能与大家分享我在这段时间里学到的东西

根据您提供的信息,我建议强制转换到对象数组并使用该信息。基本上,您可以访问以下值:

object[,] arrayValues = (object[,])ExcelRange.Value2;
arrayValues是二维数组([行,列])。Excel以极快的速度填充数组,当然数组上的操作将非常高效(不要担心装箱的性能,相信我,这不是问题)。

怎么样

public static bool IsSheetEmpty(int sheetNo)
{
    bool isEmpty = false;

    if (sheetNo <= Globals.ThisAddIn.Application.Worksheets.Count)
    {
        Worksheet ws = Globals.ThisAddIn.Application.Worksheets[sheetNo];

        if (ws.UsedRange.Address.ToString() == "$A$1" && String.IsNullOrWhiteSpace(ws.get_Range("A1").Value2))
        {
            isEmpty = true;
        }
    }
    else
    {
        // or add your own error handling when sheetNo is not found
    }

    return isEmpty;
}

momad,您的方法不错,但它(a)需要更多的工作,(b)如果某些工作表不包含数据,则会错误地将其报告为包含数据,因为UsedRange可能会受到单元格格式等因素的影响,而不仅仅是值。如果您使用
Application.WorksheetFunction.CountA
方法,那么您将拾取所有数据,并且只拾取一行中的数据,而不是五行。这两种方法肯定比使用剪贴板要好得多。剪贴板方式也会考虑带有“空白”的单元格,其他方式不会,但这是一个特例:)迈克,我不知道格式。如果是这样,那么我完全同意工作表函数CountA是一种更好的方法。但是,在我的特定场景中,我不想覆盖单元格,即使更改只是格式更改。谢谢你的澄清!
IsNullOrEmpty
不应该是
IsNullOrWhiteSpace
?如果你取一个空单元格并调用
String.Length(cell.ToString())
我认为它返回18,即使实际的单元格是空的,而且一直是空的Tanks James,我正在为excel开发一个VSTO加载项,并且经常遇到一些问题,这些问题可以由有知识的人快速回答,但在internet上查找很费时。我一定会更多地使用stackoverflow,因为这里有这么多VSTO专家@coder4life,你知道有没有办法对单元格颜色等属性进行相同的“批量”获取?几个月来,我一直在使用一种与您描述的值相同的方法,但我还没有找到一种方法,能够获取所有颜色(range.Interior.Color),而不必逐行逐列,而且速度非常慢!谢谢事实上,我为这个吸引人的问题打开了一条新的线索,只是为了让其他人更容易找到,而不是浏览评论。url是,这不意味着你知道要获取的范围吗?这也不意味着有时会过度获取所需的东西。我在读和写的时候都会用到你说的话,但是这句话虽然有效,却无助于解决眼前的问题。或者我遗漏了什么?我知道这很旧,但除了答案之外,请关闭这些事件,填充工作表,然后再打开它们:
currentInstance.EnableEvents=false/true;currentInstance.ScreenUpdate=false/true强制转换int不起作用,因为返回一个double。select和copy从来都不快;)
public static bool IsSheetEmpty(int sheetNo)
{
    bool isEmpty = false;

    if (sheetNo <= Globals.ThisAddIn.Application.Worksheets.Count)
    {
        Worksheet ws = Globals.ThisAddIn.Application.Worksheets[sheetNo];

        if (ws.UsedRange.Address.ToString() == "$A$1" && String.IsNullOrWhiteSpace(ws.get_Range("A1").Value2))
        {
            isEmpty = true;
        }
    }
    else
    {
        // or add your own error handling when sheetNo is not found
    }

    return isEmpty;
}
bool isFirstEmpty = IsSheetEmpty(1);