从 .NET 开发人员的角度理解 Excel 对象模型

摘要 :讨论了 Microsoft Office Excel 2003 提供的一些对象,并且说明了如何使用它们通过用于 Microsoft Office 系统的 Microsoft Visual Studio 工具来创建托管代码解决方案。重点主要是 Application、Workbook、Worksheet 和 Range 对象。Visual Basic .NET 和 Visual C# 代码示例演示了每个对象一些属性、方法和事件。

从 Microsoft 下载中心 下载 ExcelObj.exe。

*

本页内容
简介简介
Application 对象Application 对象
Workbook 类Workbook 类
Worksheet 类Worksheet 类
Range 对象Range 对象
下期内容下期内容

简介

对于打算利用用于 Microsoft Office 系统的 Microsoft Visual Studio 工具的开发人员和想要仅仅使用 COM 自动化来控制 Microsoft Office Excel 2003 应用程序的人来说,他们需要能够与 Excel 对象模型提供的对象进行交互。Excel 提供了数百个您可能想要与之交互的对象,但是您可以通过集中于这些可用的对象的一个非常小的子集来获得对象模型方面的一个良好的开端。这些对象包括:

• |

Application

---|---
• |

Workbook

• |

Worksheet

• |

Range

尽管不可能具体地量化,但是当您使用 Excel 时,大部分的工作将以这四个类以及它们的成员为核心。在本文档中,您将学会如何利用这些类中的每一个,另外,我们还会向您介绍每个类的一些属性、方法和事件。您也将会看到一些可以尝试的示例,这些示例演示了每个对象的一些功能。

提示 **** 总的说来,使用 Microsoft Visual Basic .NET 的开发人员在使用 Microsoft Office 对象时,相比于使用 Microsoft Visual C# 的开发人员来说要轻松得多,一个重要的原因在于:Visual Basic for Applications (VBA) 方法常包含可选参数,而 Visual Basic .NET 支持可选参数。C# 开发人员将发现他们必须为每个可选方法参数提供一个值,而 Visual Basic .NET 开发人员可以简单地使用命名的参数只提供他们需要的值。另外,C# 不支持带有参数的属性(除了索引器以外),然而,许多 Excel 属性可以接受参数。您将会发现,对于 C# 开发人员来说,一些属性(例如可用于 VBA 和 Visual Basic .NET 的 Application.Range 属性)需要单独的访问器方法( get_Range 方法替换了 Range 属性)。在本文中,请注意这样的语言之间存在的差异。

在大多数情况下,您将会发现 Excel 对象模型直接模拟其用户界面。不难猜想, Application 对象提供了封装整个应用程序的包装,并且每个 Workbook 对象都包含 Worksheet 对象的一个集合。其中,表示单元格的主要的抽象是 Range 对象,这使得您能够使用单个单元格或者单元格组。

下面的每个部分都将描述一个主要的 Excel 对象,挑选对象的特定成员来进行演示。由于可供研究的对象有数百个,所以不可能在这里对所有的对象进行深入的探讨:您将会得到足够的对象模型方面的知识来开始您的工作,并且可以使用 Excel 联机帮助来获得更详细的信息。

提示 在本文中,您将看到 DirectCastCType 方法的许多用途。其原因在于示例项目有自己的 Option Strict 设置 — 这意味着 Visual Basic .NET 需要严格的类型转换。许多 Excel 方法和属性返回 Object 类型或者依赖于晚期绑定:例如, Application.ActiveSheet 属性返回 Object ,而不是您猜想的 Worksheet 。因此,为了尽可能地进行严格的类型转换,示例启用了 Option Strict ,并且显式地处理每种类型转换。(如果不在 Visual Basic .NET 中使用 Option Strict ,您编写的代码可能编译良好,但是会在运行时失败。这就是 Option Strict 意义所在 — 它大大减少了非法转换在运行时产生异常的可能性)。如果您是一名正在阅读本文档的 C# 开发人员,您可能会赞赏这种决定。

这本白皮书引用了示例项目 ExcelObjectModel.sln。这个项目包含一个 Excel 工作簿以及相关的 Visual Basic .NET 代码。并不是本文中展示的每个示例都出现在这个示例项目中,但是需要多于一行或两行代码的任何示例都放到了工作簿中,并且在项目内设置了调用代码的超级链接。

提示 在这篇篇幅有限的文章中,不可能对每个对象或成员进行注解。甚至不可能提及这些类中的一小部分。研究任何大型对象模型最好的工具是 Object Browser 窗口,其中,您可以找到每个类的列表、以及该类的成员。您将会发现,在本文档中讨论的许多类成员适用于许多其他不同的类:例如,在 Sheets 集合的上下文中讨论的 PrintOut 方法同样适用于 ChartWorksheetRange 和其他的对象。本文档旨在让您知道什么是可用的,而剩下的东西要靠您好奇的本性来挖掘了。

返回页首 返回页首

Application 对象

Excel Application 对象代表 Excel 应用程序本身。这可能听起来是显而易见的,但是 Application 对象公开了大量关于运行时应用程序、应用到该实例的一些选项、以及在该实例内打开的当前用户对象的信息。 Application 对象提供了许多成员,其中的许多成员您从来都不需要研究,但是其他的一些成员对于您的应用程序的行为是否正确至关紧要。您可以将这些成员分为以下种类:

• |

在 Excel 中控制状态和显示的成员

---|---
• |

返回对象的成员

• |

执行操作的成员

• |

处理文件操作的成员

• |

其他成员

下面几部分介绍了这些组中的每一个、以及演示一些成员的代码示例。

在 Excel 中控制状态和显示的成员

Application 对象提供了一个大的属性集来控制 Excel 的一般状态。表 1 列出了与状态有关的 Application 对象属性的一个子集。

表 1. 一些控制 Excel 的状态的 Application 属性

属性 | 类型 | 说明

Cursor

|

XlMousePointer (xlDefault, xlIBeam, xlNorthwestArrow, xlWait)

|

获取或设置鼠标指针的外观。

EditDirectlyInCell

|

布尔值

|

直接就地获取或设置编辑单元格的能力。如果为 False,则您只能在公式栏中编辑单元格。

FixedDecimal

|

布尔值

|

如果为 True,则所有的数字值都使用 FixedDecimalPlaces 属性来确定小数位数;否则将忽略 FixedDecimalPlaces 属性(默认值为 False)。

FixedDecimalPlaces

|

Long

|

确定用于数值数据的小数位数(如果 FixedDecimal 属性为 True)。

Interactive

|

布尔值

|

获取或设置用户通过键盘和鼠标与 Excel 交互的能力;如果将此属性设置成 False,则一定要确保在异常处理程序中将其重新设置成 True。Excel 不会自动为您重新设置它。

MoveAfterReturn

|

布尔值

|

如果为 True,则当您按下 Enter 键时,选择会移到下一个单元格;默认值为 True。

MoveAfterReturnDirection

|

xlDirection (xlDown, xlToLeft, xlToRight, xlUp)

|

指示在按下 Enter 键之后移动的方向(如果 MoveAfterReturn 属性为 True)。默认值为 xlDown

ScreenUpdating

|

布尔值

|

如果为 True,Excel 就会在每个方法调用之后更新其屏幕。为了节省时间并且使您的应用程序看起来更加专业,您可以在代码运行时关掉显示。一旦完成,就一定要再次将此属性值重新设置为 True。Excel 不会自动为您重新设置它。

SheetsInNewWorkbook

|

Long

|

获取或设置 Excel 自动放置在新的工作簿中的工作表的数目。

StandardFont

|

字符串

|

获取或设置 Excel 中默认字体的名称;只有在重新启动 Excel 之后才会生效。

StandardFontSize

|

Long

|

获取或设置 Excel 中默认字体的大小;只有在重新启动 Excel 之后才会生效。

StartupPath(只读)

|

字符串

|

返回包含 Excel 启动加载项的文件夹的完整路径。

TemplatesPath(只读)

|

字符串

|

返回包含模板的文件夹的完整路径;此值代表着一个 Windows 特殊文件夹。

在表 1 所列出的所有属性中,您最可能使用的一个属性是 ScreenUpdating 属性。通过利用这个属性,您不但可以使您的 Excel 应用程序看起来更加专业,还可以使它们运行得更快 — 在每次修改后更新显示会严重影响代码的运行效率,特别是在大范围中通过编程方式填写时。然而,重要的是,当您完成您的工作时始终要设置这个属性,因为 Excel 不会为您重新设置它。因此,当使用 ScreenUpdating 属性时,您将需要始终使用如下代码片段,并且利用 .NET 异常处理来确保屏幕更新恢复:

' Visual Basic
Try
    ThisApplication.ScreenUpdating = False
    ' Do your work that updates the screen.

Finally
    ThisApplication.ScreenUpdating = True
End Try

// C#
try
{
    ThisApplication.ScreenUpdating = false;
    // Do your work that updates the screen.
}

finally
{
    ThisApplication.ScreenUpdating = true;
}

Application 对象还提供了一组控制 Excel 中的显示的属性。您可以修改这些属性中的任何一个来改变用户在屏幕上所看到的内容。 2 列出了可用的显示选项的一个子集。

表 2 一些控制 Excel 的外观的 Application 属性

属性 | 类型 | 说明

DisplayAlerts

|

布尔值

|

如果为 True(默认值),则当运行代码时,只要有必要(例如在删除一个工作表时),Excel 就会显示警告消息。设置为 False 以忽略警告。Excel 的行为就好像您已经为每个警告选择了默认值。

DisplayFormulaBar

|

布尔值

|

如果为 True(默认值),Excel 就会显示标准公式栏以编辑单元格;设置为 False 以隐藏公式栏。

DisplayFullScreen

|

布尔值

|

如果为 True,则 Excel 以全屏模式运行(这种模式与仅仅最大化 Excel 窗口的效果不一样);其默认值为 False。

提示ScreenUpdating 属性完全一样,重新设置 DisplayAlerts 属性是非常重要的。因为 Excel 不会为您重新设置此属性,并且它设置为 False,所以在您关闭工作簿之前 Excel 不会提示您保存它们;没有仔细地重新设置 DisplayAlerts 属性可能会在您不小心的情况下导致您丢失数据。

返回对象的成员

许多 Application 对象的属性返回其他的对象。因为 Visual Studio .NET 提供的标准 Microsoft Office 项目模板只包含 ThisApplicationThisWorkbook 对象,所以您通常需要利用 Application 类的对象成员来引用 Excel 提供的其他对象。您可以使用这些成员通过诸如 ActiveWindow 的属性检索对特定子对象的引用,或者通过诸如 Charts 的属性检索对一个可用的对象集的引用。 3 列出了 Application 对象的返回对象的属性的一个子集。

表 3. Application 对象的可用的返回对象的属性的一个子集。

属性 | 类型 | 说明

ActiveCell

|

范围

|

返回对活动窗口(顶部的窗口)中当前活动单元格的引用。如果没有活动窗口,此属性会产生一个错误。

ActiveChart

|

图表

|

返回对当前活动的图表的引用。对于一个嵌入式图表来说,只有当此图表被选中或被激活时才可认为是活动的。

ActiveSheet

|

对象

|

返回对活动工作簿中的活动工作表的引用。

ActiveWindow

|

窗口

|

返回对活动窗口(顶部的窗口)的引用;如果没有活动窗口,则不返回任何结果。

Charts

|

工作表

|

返回 Sheet 对象(Chart 和 Worksheet 对象的父对象)的集合,这些对象包含对活动工作簿中的每个图表的引用。

Selection

|

对象

|

返回应用程序中选中的对象。可能是一个 Range、一个 Worksheet 或任何其他的对象 — 同样适用于 Window 类,在这种情况下,选择通常是一个 Range 对象。如果当前没有对象被选中,则不返回任何结果。

Sheets

|

工作表

|

返回 Sheet 对象的集合,这些对象包含对活动工作簿中每个工作表的引用。

Workbooks

|

工作簿

|

返回 Workbook 对象的集合,这些对象包含对所有打开的工作簿的引用。

您将会最常与 Application 类的 Workbooks 属性交互。这个属性使得您能够循环访问打开的工作簿、打开或创建一个新的工作簿。下面的部分描述了这个属性的行为。

工作簿集合

Workbooks 集合使得有可能使用所有打开的工作簿、创建一个新的工作簿以及将数据导入一个新的工作簿。下表列出了您将发现的 Workbooks 集合的主要用途:

• |

创建一个新的工作簿 使用如下代码(您也可以指定一个工作簿模板的名称作为 Add 方法的一个参数):

' Visual Basic
Dim wb As Excel.Workbook = ThisApplication.Workbooks.Add()

// C#
Excel.Workbook wb = ThisApplication.Workbooks.Add(Type.Missing);

---|---
• |

关闭所有打开的工作簿 。与大多数的集合不同,这个集合允许您一次性地关闭所有的成员。下面的方法调用关闭所有打开的工作簿:

' Visual Basic
ThisApplication.Workbooks.Close()

// C#
ThisApplication.Workbooks.Close();

• |

打开一个现有的工作簿 (使用 Workbooks 集合的 Open 方法)。最简单的形式是使用 Open 方法,如下面的代码片段所示。 Open 方法提供了大量的可选参数,这些参数会影响它在特定环境中的行为,但是,您通常不需要使用这些可选参数:

' Visual Basic
Dim wb As Excel.Workbook = _
  ThisApplication.Workbooks.Open("C:\YourPath\YourWorkbook.xls")

// C#
Excel.Workbook wb = ThisApplication.Workbooks.Open( 
    "C:\\YourPath\\Yourworkbook.xls", 
    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);

提示 如果您是一名 C# 开发人员,您将习惯于在方法调用中看到对 Type.Missing 值的引用。因为 Excel 对象模型是以 VBA 为目标编写的,所以它的许多方法接受可选参数 — 有时达到 30 个可选参数。您将需要使用 Type.Missing 值的许多实例,或者提供每个参数的特定默认值。

• |

以工作簿的形式打开一个文本文件、数据库或 XML 文件(使用 OpenTextOpenDatabaseOpenXml )。这些方法提供了极大的灵活性,但即使是对它们进行简单的介绍,也会占用比这里安排的多得多的篇幅。就现在而言,您知道这些方法存在就足够了 — 如果您需要将这些项中的任何一个加载到 Excel 中,您可以更仔细地研究这些项。您可以使用如下代码以工作簿的形式加载一个文本文件(使用逗号作为分隔符,从文本文件中的第三行开始):

' Visual Basic
Dim wb as Excel.Workbook = _
    ThisApplication.Workbooks.OpenText("C:\Test.txt", StartRow:=3, _
    DataType:=xlDelimited, Comma:=True)

// C#
Excel.Workbook wb = 
    ThisApplication.Workbooks.OpenText("C:\\Test.txt", 
    Type.Missing, 3, Excel.XlTextParsingType.xlDelimited, 
    Excel.XlTextQualifier.xlTextQualifierDoubleQuote, 
    Type.Missing, Type.Missing, Type.Missing, True, 
    Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing);

• |

引用单个工作簿 。您可以使用整数(指示在集合中的位置)或工作簿名作为 Workbooks 集合中的索引。然而,如果您想要通过名称引用工作簿,您将需要注意对其进行引用的方法:您必须使用您在标题栏看到的名称,在保存该文件之前,这个名称不包括“.xls”扩展名:

' Visual Basic
Dim wb As Excel.Workbook = ThisApplication.Workbooks(1)
' Before Book1 is saved:
wb = ThisApplication.Workbooks("Book1")
' After Book1 is saved:
wb = ThisApplication.Workbooks("Book1.xls")

// C#
Excel.Workbook wb = ThisApplication.Workbooks[1];
// Before Book1 is saved:
wb = ThisApplication.Workbooks["Book1"];
// After Book1 is saved:
wb = ThisApplication.Workbooks["Book1.xls"];

提示 当您引用特定的工作簿时,您利用的是默认的索引器(Item 属性)。除了 Item 属性之外, Workbooks 集合像 Microsoft Office 提供的所有集合一样,包括 Count 属性, Count 属性返回集合中的项(本例中的 Workbooks )的数目。

执行操作的成员

Application 对象提供了许多允许您执行操作(从重新计算当前数据到撤销对数据的更改)的方法。下表枚举了 Application 对象的一些方法,并且使用了一些小例子对每个方法进行了描述。这一部分的示例出现在示例工作簿中的 Application Object 工作表内:

• |

Calculate :强制重新计算所有打开的工作簿、特定的工作簿或者特定的范围:

' Visual Basic
ThisApplication.Calculate
' Or...
ThisWorkbook.Calculate
' Or...
ThisApplication.Range("SomeNamedRange").Calculate

// C#
ThisApplication.Calculate();
// Or...
ThisWorkbook.Calculate();
// Or...
ThisApplication.get_Range("A1", "B12").Calculate();

正如示例代码中所示, RangeWorksheet 对象也提供 Calculate 方法。使用可以将计算范围限定在您想要重新计算的最小单元格数内的对象的方法。Excel 中的重新计算引擎非常快,但是如果您可以限制所涉及到的单元格数,您就可以优化这一操作。只有在您想重新计算每个打开的工作簿中的每个未决更改时才使用 Application.Calculate

提示 Visual Basic .NET 和 C# 在处理 Excel 成员时并不完全一样。例如,Excel、VBA 和 Visual Basic .NET 中的 Range 属性在 C# 中只能通过 get_Range 方法进行访问。在本文中,您将会发现此访问器成员和其他访问器成员的一些例子。

---|---
• |

Checkspelling :返回一个 Boolean 来指示提供的参数是否拼写正确。您可以选择提供一个自定义字典的名称和一个 Boolean 来指示您是否想要忽略大小写。下面的代码片段检查您所提供的值的拼写,并且在工作表上指示其结果:

' Visual Basic
Private Sub TestSpelling()
    Dim rng As Excel.Range = _
      ThisApplication.Range("CheckSpelling")
    Dim strOut As String

    If ThisApplication.CheckSpelling( _
      rng.Offset(0, 1).Value.ToString) Then
        strOut = "Spelled correctly"
    Else
        strOut = "Spelled incorrectly"
    End If
    rng.Offset(0, 2).Value = strOut
End Sub

// C#
private void TestSpelling()
{
    // If you specify only a named range in the call 
    // to get_Range, use Type.Missing for the second parameter.
    Excel.Range rng = ThisApplication.
    get_Range("CheckSpelling", Type.Missing);

    // Note that C# requires you to retrieve and set
    // the Value2 property of the Range, rather than 
    // the Value property, because the Value property 
    // is parameterized, making it unavailable to C# code:
    rng.get_Offset(0, 2).Value2 = 
        (ThisApplication.CheckSpelling(
    rng.get_Offset(0, 1).Value2.ToString(), 
        Type.Missing, Type.Missing) 
    ? "Spelled correctly" 
    : "Spelled incorrectly");
}

提示 前面的代码片段使用了 Range 对象的 Offset 方法,到目前为止您还都没有遇到过。在本文后面讨论 Range 对象的部分中将对这二者进行讨论。 Range 类的使用很容易理解: Range 对象代表一个单元格或者一组单元格。在本例中, Range 对象引用已命名范围 CheckSpellingOffset 属性从相关 Range 的左上角的指定行数和列数处返回一个 Range 对象,并且允许您处理相对于一个已知位置的单元格。

• |

Evaluate :将 Excel 名称转换成实际的引用或值。这个方法允许您以字符串的形式创建引用,并且在需要时将其转换成一个实际对象引用,或者求表达式的值。下面的示例允许您将单元格的地址输入到示例工作表中,并且该代码将文本放到您指定地址的单元格中:

' Visual Basic
Private Sub TestEvaluate()
    Dim rng As Excel.Range = _
      ThisApplication.Range("Evaluate")

    Try
        Dim rngNew As Excel.Range = _
          ThisApplication.Evaluate( _
          DirectCast(rng.Offset(0, 1).Value), Excel.Range)
        rngNew.Value = "Hello, World!"
    Catch ex As Exception
        MessageBox.Show(ex.Message, ThisApplication.Name)
    End Try
End Sub

// C#
private void TestEvaluate()
{
    Excel.Range rng = ThisApplication.
        get_Range("Evaluate", Type.Missing);

    try 
    {
        Excel.Range rngNew = 
            (Excel.Range) ThisApplication.Evaluate(
            rng.get_Offset(0, 1).Value2);
        rngNew.Value2 = "Hello, World!";
    } 
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, ThisApplication.Name);
    }
}

• |

MailSystemMailSessionMailLogoffMailLogonSendMail :这些成员允许您登录您所安装的电子邮件系统、将当前的工作簿作为附件发送、以及从您所安装的电子邮件系统中注销。 MailSystem 属性指出已安装的电子邮件系统,而 MailSession 属性返回对当前电子邮件会话(如果有活动的会话,您就不需要登录)的引用。下面的示例将示例工作簿作为一个简单的电子邮件消息的附件发送:

' Visual Basic
Private Sub TestEmail()
    If ThisApplication.MailSystem = Excel.XlMailSystem.xlMAPI Then
        If ThisApplication.MailSession Is Nothing Then
            Dim frm As New SendMail
            If frm.ShowDialog = DialogResult.OK Then
              ThisApplication.MailLogon( _
              frm.EmailName, frm.EmailPassword, frm.DownloadNewMail)
            End If
        End If
        Dim strEmail As String = _
         ThisApplication.Range("SendMail").Offset(0, 1). _
         Value.ToString
        ThisWorkbook.SendMail(strEmail, "Sample Excel Email")
        ThisApplication.MailLogoff()
    Else
        MessageBox.Show( _
         "This demonstration works only if MAPI is installed.")
    End If
End Sub

// C#
private void TestEmail()
{
    if (ThisApplication.MailSystem == 
        Excel.XlMailSystem.xlMAPI ) 
    {
        if ( ThisApplication.MailSession == null ) 
        {
            SendMail frm = new SendMail();
            if (frm.ShowDialog() == DialogResult.OK )
            {
                ThisApplication.MailLogon(frm.EmailName, 
                    frm.EmailPassword, frm.DownloadNewMail);
            }
        }
        string  strEmail = ThisApplication.
            get_Range("SendMail", Type.Missing).
            get_Offset(0, 1).Value2.ToString();
        ThisWorkbook.SendMail(strEmail, 
            "Sample Excel Email", Type.Missing);
        ThisApplication.MailLogoff();
    } 
    else 
    {
        MessageBox.Show("This demonstration works only if " + 
            "MAPI is installed.");
    }
}

Workbook 类提供了 SendMail 方法;这是很有意义的,因为可以通过电子邮件发送的最小粒度的对象就是工作簿本身。您会注意到, SendMail 方法并没有提供任何将文本附加到您所发送的消息的方法,并且寻址方面也不够灵活。很明显,提供这些成员只是使通过电子邮件发送一个工作簿变得容易。如果您想获得功能更加齐全的支持,则您需要研究其他与电子邮件交互的方法。此外,如果您当前不在线,并且没有连接到您的电子邮件系统,则上面的示例代码将失败。如果 MailSession 属性没有返回任何结果,则您可以处理这种失败情况,并且不再尝试发送邮件。

• |

Quit :允许您通过编程方式退出 Excel。如果您将 DisplayAlerts 属性设置为 False,则系统不会提示您保存任何未保存的数据。此外,如果您将 WorkbookSaved 属性设置为 True,则不管您有没有进行更改,Excel 都不会提示您保存它:

' Visual Basic
ThisApplication.Quit

// C#
ThisApplication.Quit();

• |

Undo :取消用户在用户界面内进行的最后一次操作。这个方法不会对代码进行的操作产生影响,并且只能撤销单个操作。这项功能并不是十分的强大,但是它确实可以使您在执行您的代码之前撤销用户进行的最后一次操作:

' Visual Basic
ThisApplication.Undo

// C#
ThisApplication.Undo();

处理文件操作的成员

Application 对象提供了几个成员,通过这些成员,您可以与 Excel 应用程序的上下文内的文件系统交互。下面几部分描述了您可能会使用到的一些成员。(这部分所描述的示例在示例工作簿的 Application File Handling 工作表中。)

DefaultFilePath 属性

这个简单的属性获取或者设置 Excel 用于加载和保存文件的路径:

' Visual Basic
' When the workbook opens:
ThisApplication.Range("DefaultFilePath").Value = _
  ThisApplication.DefaultFilePath

' When you save the DefaultFilePath property:
ThisApplication.DefaultFilePath = _
  ThisApplication.Range("DefaultFilePath"). _
  Value.ToString

// C#
// When the workbook opens:
ThisApplication.get_Range("DefaultFilePath", Type.Missing).
    Value2 = ThisApplication.DefaultFilePath;

// When you save the DefaultFilePath property:
ThisApplication.DefaultFilePath = 
    ThisApplication.get_Range("DefaultFilePath", Type.Missing).
    Value2.ToString();

DefaultSaveFormat 属性

此属性获取或者设置保存工作簿的默认格式。Excel 为此属性提供了大量的选项,这些选项都是 XlFileFormat 枚举的成员。示例工作簿允许您从可选项中进行选择,如 1 所示。下面的代码片段演示了示例如何加载和保存此属性的值。

在这个例子中,示例工作表中的列 E 包含 XlFileFormat 枚举(在名为“ XlFileFormat ”的范围中)的所有可能的值的名称列表,而列 F 包含相应的整数值。 2 展示了这两个列的一个子集。 DefaultSaveFormat 命名范围(在 1 中)包含对 XlFileFormat 范围的引用,这使得您可以从一个列表中进行选择。一旦您选择保存该值,代码就必须使用 Range.Find 方法找到您已经选择的字符串,然后使用 Range.Offset 方法以您找到的值的指定偏移量返回一个值。(有关 Range.Find 方法的详细信息,请参阅本文后面标题为“在范围内搜索”的部分。)最后,代码将整数值(转换成适当的枚举类型)重新保存到 DefaultSaveFormat 属性。

检索 DefaultSaveFormat 的当前值非常简单。下面的代码将值转换成文本,并且在示例工作表上的正确 Range 中显示它:

' Visual Basic
' When the workbook opens, convert the enumerated value 
' into a string:
ThisApplication.Range("DefaultSaveFormat").Value = _
  ThisApplication.DefaultSaveFormat.ToString

// C#
// When the workbook opens, convert the enumerated value 
// into a string:
ThisApplication.get_Range("DefaultSaveFormat", Type.Missing).
    Value2 = ThisApplication.DefaultSaveFormat.ToString();

重新赋选定的值要困难一些。这涉及到三个步骤。代码必须处理下列任务:

从工作表上的 DefaultSaveFormat 范围检索选择的保存格式的名称:

' Visual Basic
' Retrieve the name of the new save format, as a string:
Dim strSaveFormat As String = _
  ThisApplication.Range("DefaultSaveFormat"). _
  Value.ToString()

// C#
// Retrieve the name of the new save format,
// as a string:
string strSaveFormat = ThisApplication.
  get_Range("DefaultSaveFormat", Type.Missing).
  Value2.ToString();

在工作表上临近 XlFileFormat 范围的列中查找相匹配的整数值(调用 Range 类的 Find 方法)。然后,代码使用 Range.Offset 属性来检索右边一列的值:

' Visual Basic
Dim intSaveFormat As Integer = _
  CType(ThisApplication.Range("XlFileFormat"). _
  Find(strSaveFormat).Offset(0, 1).Value, Integer)

// C#
Excel.Range rng = ThisApplication.
    get_Range("xlFileFormat", Type.Missing);
Excel.Range rngFind = rng.Find(strSaveFormat, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Excel.XlSearchDirection.xlNext, Type.Missing, Type.Missing, 
    Type.Missing);
// In C#, use the get_Offset method instead of the Offset property:
int intSaveFormat = 
    Convert.ToInt32(rngFind.get_Offset(0, 1).Value2);

将整数值重新赋值给 DefaultSaveFormat 属性:

' Visual Basic
ThisApplication.DefaultSaveFormat = _
  CType(intSaveFormat, Excel.XlFileFormat)

// C#
ThisApplication.DefaultSaveFormat = 
  Excel.XlFileFormat) intSaveFormat;

1. 从可用类型的列表中选择一种文件格式。

2. 示例工作表上的 XlFileFormat 范围的一个子集。

RecentFiles 属性

RecentFiles 属性返回一个字符串的集合,包含出现在“文件”菜单的最近使用的文件列表内的所有文件的名称。这个列表的长度将随着用户已经选择保留的文件的数目的变化而变化。示例工作簿在其打开时调用这一过程,将最近的文件列表复制到示例工作表上一个名为 RecentFiles 的范围中:

' Visual Basic
Private Sub ListRecentFiles()
    Dim i As Integer
    Dim rng As Excel.Range = DirectCast( _
      ThisApplication.Range("RecentFiles"). _
      Cells(1, 1), Excel.Range)
    For i = 1 To ThisApplication.RecentFiles.Count
        rng.Offset(i - 1, 0).Value = _
          ThisApplication.RecentFiles(i).Name
    Next
End Sub

// C#
private void ListRecentFiles()
{
    Excel.Range rng = (Excel.Range)ThisApplication.
        get_Range("RecentFiles", Type.Missing).Cells[1, 1];

    for (int i = 1; i <= ThisApplication.RecentFiles.Count; i++)
    {
        rng.get_Offset(i - 1, 0).Value2 = 
            ThisApplication.RecentFiles[i].Name;
    } 
}

FileDialog 属性

FileDialog 属性返回 FileDialog 对象,这个对象处理四种类型的文件操作。由该属性返回的这个 FileDialog 对象允许您:

• |

选择一个文件,并且将其打开。

---|---
• |

选择一个文件位置,并且保存当前工作簿。

• |

选择一个文件夹。

• |

选择一个文件名。

通过使用这个对话框,您可以利用 Microsoft Office 提供的所有文件处理功能。 FileDialog 属性需要您通过传递给它一个 msoFileDialogType 枚举值( msoFileDialogFilePickermsoFileDialogFolderPickermsoFileDialogOpenmsoFileDialogSaveAs )来选择对话框的特定使用。然后,您就可以与这个属性返回的 FileDialog 对象进行交互了。

与许多其他的对象相似, FileDialog 对象是由 Microsoft.Office.Core 命名空间提供的。为了避免键入每个 Office 对象的完整路径,示例项目使用 Importsusing 语句来导入这个命名空间。本文中的代码片段还假定您已经将适当的命名空间引用添加到您的文件中了:

' Visual Basic 
Imports Office = Microsoft.Office.Core

// C#
using Office = Microsoft.Office.Core;

FileDialog 对象的 Show 方法显示对话框,并且返回 -1(如果您按 OK)和 0(如果您按 Cancel)。如果您已经使用了 msoFileDialogOpenmsoFileDialogSaveAs 枚举值,您可以使用该类的 Execute 方法来实际打开或者保存文件。 SelectedItems 属性包含一个字符串的集合,每个字符串代表一个选择的文件名。

例如,下面来自示例工作簿的代码提示您打开一个新的工作簿。这个代码片段允许多重选择、清除可用筛选器的列表、添加两个新的筛选器,然后显示对话框,如 3 所示。如果您选择一个文件或多个文件,则代码会调用 FileDialog 对象的 Execute 方法来打开请求的文件:

' Visual Basic
With ThisApplication.FileDialog( _
  Office.MsoFileDialogType.msoFileDialogOpen)
    .AllowMultiSelect = True
    .Filters.Clear
    .Filters.Add "Excel Files", "*.xls;*.xlw"
    .Filters.Add "All Files", "*.*"
    If .Show <> 0 Then
        .Execute
    End If
End With

// C#
dlg = ThisApplication.get_FileDialog(
    Office.MsoFileDialogType.msoFileDialogOpen);
dlg.Filters.Clear();
dlg.Filters.Add("Excel Files", "*.xls;*.xlw", Type.Missing);
dlg.Filters.Add("All Files", "*.*", Type.Missing);
if(dlg.Show() != 0)
    dlg.Execute();

3. 使用 FileDialog 类来显示标准 File Open 对话框。

下面来自示例的代码片段演示了您可以如何使用该对话框来选择一个文件夹:

' Visual Basic
With ThisApplication.FileDialog( _
  Office.MsoFileDialogType.msoFileDialogFolderPicker)
    If .Show <> 0 Then
        ThisApplication.Range("FolderPickerResults"). _
          Value = .SelectedItems.Item(1)
    End If
End With

// C#
dlg = ThisApplication.get_FileDialog(
    Office.MsoFileDialogType.msoFileDialogFolderPicker);
if (dlg.Show() != 0)
{
    ThisApplication.get_Range("FolderPickerResults", Type.Missing).
        Value2 = dlg.SelectedItems.Item(1);
}

Application 对象还提供了 GetOpenFileNameGetSaveAsFileName 方法,这些方法允许您选择一个要打开的文件的文件名。尽管您可以使用这些方法,但是您将发现 Microsoft .NET Framework 提供的相对应的 OpenFileDialogSaveFileDialog 控件功能更加丰富,而且更加易于使用。

其他有用的成员

Application 对象提供了一些不适用于其他种类的成员,例如 WorksheetFunction 属性、 Names 集合和 Windows 集合。下面几部分将描述这些成员。

WorksheetFunction

Application 对象包含一个属性 WorksheetFunction ,这个属性返回 WorksheetFunction 类的实例。这个类提供了许多共享/静态方法,其中的每个方法都包装了一个 Excel 工作表函数。这些方法中的每一个都公开许多 Excel 电子表格计算函数中的一个,而 VBA 没有提供这些函数。而且其中的一些成员在 Visual Basic .NET 和 C# 的运算符和方法中已经具备,因此您不大可能会使用这些成员(例如,And 方法)。

您在 WorksheetFunction 类的方法中将会发现大量有趣的和有用的函数,总结在下面的列表中:

• |

数学函数 ,例如 AcosAcoshAsinAsinhCoshDegreesLnLogMedianMaxMinModeRadians 等等。

---|---
• |

域函数 ,允许您对范围执行运算,例如 DAverageDCountDCountADGetDMaxDMinDProductDSum 等等。

• |

逻辑函数 ,例如 IsErrIsErrorIsLogicalIsNAIsNonTextIsNumberIsText

• |

统计函数 ,例如 BetaDistBinomDistChiTestChiInvLogNormDistNegBinomDistPearsonSumProductSumSqTDistTTest , VarVarP 等等。

• |

电子表格函数 ,在 .NET Framework 中,您不大可能会使用这些函数,例如 AndOrChoose 等等。

• |

与泰国有关的函数:您将会发现大量使人莫名其妙的函数,这些函数用于处理泰国数字、日历和货币(谣传 Excel 小组曾经特别喜欢吃泰国食品,因而添加了这些函数来帮助计算他们在当地泰国餐馆的餐费,但是现在看来这个谣言是不真实的),例如 BahtTextIsThaiDigitThaiDayOfWeekThaiDigitThaiMonthOfYearThaiNumSoundThaiNumStringThaiStringLengthThaiYearRoundBahtDownRoundBahtUp

在 Visual Studio .NET 项目中,利用 WorksheetFunction 类非常容易。因为项目模板为您提供了 ThisApplication 对象,您可以简单地引用该对象的 WorksheetFunction 属性。示例应用程序包含一个名为 Other Application Members 的工作表,如图 4 所示,这个示例只测试了这个类的几个成员。

WorksheetFunction 类及其成员提供了一个好例子,说明了为什么从 Visual Basic 中使用 Excel 对象要比从 C# 中使用等效的代码容易得多。 WorksheetFunction 类的许多方法要求 C# 开发人员传递 30 个参数,其中的大多数为空。当然,通过编写封装各种不同的方法组(一些具有一个必需的参数,一些具有两个必需的参数,等等)的包装无疑可以减轻这种负担。出于本文的目的,代码调用“裸”方法,而不使用包装方法。当然,C# 代码很难看。

单击 Demonstrate WorksheetFunction 链接运行下面的代码(有关 Sort 方法的详细信息,请参阅“对范围内的数据进行排序”部分):

' Visual Basic
Private Sub TestWorksheetFunction()
    Dim ws As Excel.Worksheet = _
      DirectCast(ThisWorkbook.ActiveSheet, Excel.Worksheet)
    Dim rng As Excel.Range = ws.Range("RandomNumbers")
    Dim rnd As New System.Random

    Dim i As Integer
    For i = 1 To 20
        ws.Cells(i, 2) = rnd.Next(100)
    Next i
    rng.Sort(rng, _
      Orientation:=Excel.XlSortOrientation.xlSortColumns)

    With ThisApplication.WorksheetFunction
        ws.Range("Min").Value = .Min(rng)
        ws.Range("Max").Value = .Max(rng)
        ws.Range("Median").Value = .Median(rng)
        ws.Range("Average").Value = .Average(rng)
        ws.Range("StDev").Value = .StDev(rng)
    End With
End Sub

// C#
private void TestWorksheetFunction() 
{
    Excel.Worksheet ws = (Excel.Worksheet) ThisWorkbook.ActiveSheet;
    Excel.Range rng = ws.get_Range("RandomNumbers", Type.Missing);
    System.Random rnd = new System.Random();

    for ( int i = 1 ; i <= 20; i++)
        ws.Cells[i, 2] = rnd.Next(100);

    rng.Sort(rng, Excel.XlSortOrder.xlAscending, 
        Type.Missing, Type.Missing, Excel.XlSortOrder.xlAscending, 
        Type.Missing, Excel.XlSortOrder.xlAscending, 
        Excel.XlYesNoGuess.xlNo, Type.Missing,Type.Missing, 
        Excel.XlSortOrientation.xlSortColumns, 
        Excel.XlSortMethod.xlPinYin, 
        Excel.XlSortDataOption.xlSortNormal, 
        Excel.XlSortDataOption.xlSortNormal, 
        Excel.XlSortDataOption.xlSortNormal);

    Excel.WorksheetFunction wsf = ThisApplication.WorksheetFunction;
    ws.get_Range("Min", Type.Missing).Value2 = wsf.Min(rng, 
        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);
    ws.get_Range("Max", Type.Missing).Value2 = wsf.Max(rng, 
        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);
    ws.get_Range("Median", Type.Missing).Value2 = wsf.Median(rng,
        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);
    ws.get_Range("Average", Type.Missing).Value2 = wsf.Average(rng, 
        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);
    ws.get_Range("StDev", Type.Missing).Value2 = wsf.StDev(rng, 
        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);
}

4. 选择 WorksheetFunction 工作表来检验 WorksheetFunction 类及其有用的方法。

正如您在示例代码中看到的,您可以把 Range 对象作为参数传递给 WorksheetFunction 方法。此外,您也可以将单值或值列表作为参数进行传递。这些方法通常可接受多达 32 个参数,因此,如果您想要计算一个固定的数字列表的平均值,您可以使用如下代码:

' Visual Basic
dblAverage = ThisApplication.WorksheetFunction.Average( _
 12, 14, 13, 19, 21)

// C#
// Note the number of Type.Missing values--the method accepts
// 30 parameters.
dblAverage = ThisApplication.WorksheetFunction.Average(
    12, 14, 13, 19, 21, 
    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);

Window 类和 Windows 集合

正如您可能期望的, Application 对象提供了对 Excel 应用程序内显示的窗口的控制,并且您可以使用 Application 对象的 Windows 属性来打开、关闭和排列 Excel 对象窗口。

Windows 属性返回 Window 对象的集合,并且您可以调用 Arrange 方法来排列所有打开的窗口(或者只是可见的窗口)。指定一个 XlArrangeStyle 枚举值来指示您想要以何种方式排列窗口,并且还可以选择指定一些关于您是否只想排列可见的窗口、以及您想如何同步窗口滚动的信息。例如,要在 Excel 工作区中平铺显示窗口,您可以使用如下代码:

' Visual Basic
ThisApplication.Windows.Arrange( _
  Excel.XlArrangeStyle.xlArrangeStyleTiled)

// C#
ThisApplication.Windows.Arrange( 
  Excel.XlArrangeStyle.xlArrangeStyleTiled, 
  Type.Missing, Type.Missing, Type.Missing);

如果您想要通过编程方式创建一个新的窗口,您可以调用工作簿的 NewWindow 方法,例如:

' Visual Basic
ThisWorkbook.NewWindow()

// C#
ThisWorkbook.NewWindow();

因为 NewWindow 方法返回 Window 对象,所以您也可以编写如下代码,它设置新窗口的标题,然后并将其激活:

' Visual Basic
With ThisWorkbook.NewWindow()
    .Caption = "New Window"
    .Activate()
End With

// C#
Excel.Window wnd = ThisWorkbook.NewWindow();
wnd.Caption = "New Window";
wnd.Activate();

Windows 类提供控制相关窗口的外观和行为的属性和方法,包括颜色、标题、窗口特性的可视性、以及滚动行为。您可以编写如下代码来使用特定窗口的属性:

' Visual Basic
With ThisApplication.Windows(3)
    .GridlineColor = ColorTranslator.ToOle(Color.Red)
    .Caption = "A New Window"
    .DisplayHeadings = False
    .DisplayFormulas = False
    .DisplayWorkbookTabs = False
    .SplitColumn = 1
End With

// C#
wnd = ThisApplication.Windows[3];
wnd.GridlineColor = ColorTranslator.ToOle(Color.Red);
wnd.Caption = "A New Window";
wnd.DisplayHeadings = false;
wnd.DisplayFormulas = false;
wnd.DisplayWorkbookTabs = false;
wnd.SplitColumn = 1;

提示 虽然 VBA 和 .NET 都通过相似的范式使用颜色 — 每种都使用三个一组的字节,包含颜色中红、绿和蓝组成部分,编码成 32 位整数的三个低位字节 — 但是它们处理颜色的方式不同。您可以使用 System.Drawing.ColorTranslator.ToOle 方法从 .NET 颜色转换到 VBA 所需的 OLE 颜色。

单击 Other Application Members 工作表上的 Work with Windows 会运行示例程序 TestWindows,它包含这一部分中以小程序块的形式提供的所有代码。单击相同的工作表中的 Reset Windows 会运行下面的过程,它将关闭除了第一个窗口以外的所有窗口,然后把第一个窗口最大化:

' Visual Basic
Private Sub ResetWindows()
    Dim i As Integer
    For i = ThisApplication.Windows.Count To 2 Step -1
        ThisApplication.Windows(i).Close()
    Next
    ThisApplication.Windows(1).WindowState = _
      Excel.XlWindowState.xlMaximized
End Sub

// C#
private void ResetWindows()
{
    for (int i = ThisApplication.Windows.Count; i >= 2; i--)
        ThisApplication.Windows[i].Close(
          false, Type.Missing, Type.Missing);
    ThisApplication.Windows[1].WindowState = 
        Excel.XlWindowState.xlMaximized;
}

Name 类和 Names 集合

Application 对象提供了它的 Names 属性,这个属性返回 Name 对象的集合。每个 Name 对象都对应于 Excel 应用程序中的命名范围。有许多检索对命名范围的引用的方法 — 您可以使用 Workbook 对象的 Names 属性,也可以使用 Worksheet 对象的 Names 属性。

为了创建一个新的命名范围,可以使用 Names 集合的 Add 方法,如下面的代码片段所示。除了两个必需的参数之外, Add 方法还接受许多可选的参数:

' Visual Basic
Dim nm As Excel.Name
nm = ThisApplication.Names.Add( _
  "NewName", "='Other Application Members'!$A$6")

// C#
Excel.Name nm;

nm = ThisApplication.Names.Add(
    "NewName", @"='Other Application Members'!$A$6", 
    Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing);

指定名称和位置(以及其他可选的参数),然后,您就可以在您的代码中引用该范围:

' Visual Basic 
ThisApplication.Range("NewName").Value = "Hello, World!"

// C#
ThisApplication.get_Range(
    "NewName", Type.Missing).Value2 = "Hello, World!";

为了检索有关命名范围的信息,您可以使用 Name 类的各种属性。下面的列表描述了一些最常用的成员:

• |

Name 返回分配给命名范围的名称。

---|---
• |

RefersTo 以标准格式 ("=SheetName!$B$25") 返回一个包含实际目标地址的字符串。

• |

RefersToR 1C 1 以“R1C1”格式 ("=SheetName!R25C2") 返回目标地址。

• |

Value 返回对解析为范围的内容的命名范围的引用。

单击示例中的 Work with Names 链接运行下面的代码,用关于所有命名范围的信息填充工作表的一个区域:

' Visual Basic
Dim nm As Excel.Name
Dim rng As Excel.Range = ThisApplication.Range("Names")
Dim i As Integer

For i = 0 To ThisApplication.Names.Count – 1
    nm = ThisApplication.Names.Item(i + 1)
    rng.Offset(i, 0).Value = nm.Name
    ' Without the leading "'", these references
    ' get evaluated, rather than displayed directly.
    rng.Offset(i, 1).Value = "'" & nm.RefersTo.ToString
    rng.Offset(i, 2).Value = "'" & nm.RefersToR1C1.ToString
    rng.Offset(i, 3).Value = nm.Value
Next i

// C#
Excel.Range rng = ThisApplication.get_Range("Names", Type.Missing);
for ( int i = 0 ; i <= ThisApplication.Names.Count - 1; i++)
{
    nm = ThisApplication.Names.Item(i + 1, 
        Type.Missing, Type.Missing);
    rng.get_Offset(i, 0).Value2 = nm.Name;
    // Without the leading "'", these references
    // get evaluated, rather than displayed directly.
    rng.get_Offset(i, 1).Value2 = "'" + nm.RefersTo.ToString();
    rng.get_Offset(i, 2).Value2 = "'" + nm.RefersToR1C1.ToString();
    rng.get_Offset(i, 3).Value2 = nm.Value;
}

Application 事件

除了 Application 类提供的所有其他方法之外,您还将发现有一大组事件可用。虽然不可

Published At
Categories with Web编程
Tagged with
comments powered by Disqus