Excel 對象模型

摘要:討論了 Microsoft Office Excel 2003 提供的一些對象,並且說明了如何使用它們通過用於 Microsoft Office 系統的 Microsoft Visual Studio 工具來創建託管代碼解決方案。重點主要是 Application、Workbook、Worksheet 和 Range 對象。Visual Basic .NET 和 Visual C# 代碼示例演示了每個對象一些屬性、方法和事件。


從 下載 ExcelObj.exe。


*

本頁內容

簡介


對於打算利用用於 Microsoft Office 系統的 Microsoft Visual Studio 工具的開發人員和想要僅僅使用 COM 自動化來控制 Microsoft Office Excel 2003 應用程序的人來說,他們需要能夠與 Excel 對象模型提供的對象進行交互。Excel 提供了數百個您可能想要與之交互的對象,但是您可以通過集中於這些可用的對象的一個非常小的子集來獲得對象模型方面的一個良好的開端。這些對象包括:


儘管不可能具體地量化,但是當您使用 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 聯機幫助來獲得更詳細的信息。


提示 在本文中,您將看到 DirectCast 和 CType 方法的許多用途。其原因在於示例項目有自己的 OptionStrict 設置 — 這意味着 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 方法同樣適用於 Chart、Worksheet、Range 和其他的對象。本文檔旨在讓您知道什麼是可用的,而剩下的東西要靠您好奇的本性來挖掘了。



Application 對象


Excel Application 對象代表 Excel 應用程序本身。這可能聽起來是顯而易見的,但是 Application 對象公開了大量關於運行時應用程序、應用到該實例的一些選項、以及在該實例內打開的當前用戶對象的信息。Application 對象提供了許多成員,其中的許多成員您從來都不需要研究,但是其他的一些成員對於您的應用程序的行爲是否正確至關緊要。您可以將這些成員分爲以下種類:


下面幾部分介紹了這些組中的每一個、以及演示一些成員的代碼示例。


在 Excel 中控制狀態和顯示的成員


Application 對象提供了一個大的屬性集來控制 Excel 的一般狀態。表 1 列出了與狀態有關的 Application 對象屬性的一個子集。



在表 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 列出了可用的顯示選項的一個子集。



提示 與 ScreenUpdating 屬性完全一樣,重新設置 DisplayAlerts 屬性是非常重要的。因爲 Excel 不會爲您重新設置此屬性,並且它設置爲 False,所以在您關閉工作簿之前 Excel 不會提示您保存它們;沒有仔細地重新設置 DisplayAlerts 屬性可能會在您不小心的情況下導致您丟失數據。


返回對象的成員


許多 Application 對象的屬性返回其他的對象。因爲 Visual Studio .NET 提供的標準 Microsoft Office 項目模板只包含 ThisApplication 和 ThisWorkbook 對象,所以您通常需要利用 Application 類的對象成員來引用 Excel 提供的其他對象。您可以使用這些成員通過諸如 ActiveWindow 的屬性檢索對特定子對象的引用,或者通過諸如 Charts 的屬性檢索對一個可用的對象集的引用。表 3 列出了 Application 對象的返回對象的屬性的一個子集。



您將會最常與 Application 類的 Workbooks 屬性交互。這個屬性使得您能夠循環訪問打開的工作簿、打開或創建一個新的工作簿。下面的部分描述了這個屬性的行爲。


工作簿集合


Workbooks 集合使得有可能使用所有打開的工作簿、創建一個新的工作簿以及將數據導入一個新的工作簿。下表列出了您將發現的 Workbooks 集合的主要用途:


執行操作的成員


Application 對象提供了許多允許您執行操作(從重新計算當前數據到撤銷對數據的更改)的方法。下表枚舉了 Application 對象的一些方法,並且使用了一些小例子對每個方法進行了描述。這一部分的示例出現在示例工作簿中的 ApplicationObject 工作表內:


處理文件操作的成員


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 枚舉值(msoFileDialogFilePicker、msoFileDialogFolderPicker、msoFileDialogOpen 或 msoFileDialogSaveAs)來選擇對話框的特定使用。然後,您就可以與這個屬性返回的 FileDialog 對象進行交互了。


與許多其他的對象相似,FileDialog 對象是由 Microsoft.Office.Core 命名空間提供的。爲了避免鍵入每個 Office 對象的完整路徑,示例項目使用 Imports 或 using 語句來導入這個命名空間。本文中的代碼片段還假定您已經將適當的命名空間引用添加到您的文件中了:

 Visual Basic 
Imports Office = Microsoft.Office.Core
// C#
using Office = Microsoft.Office.Core;

FileDialog 對象的 Show 方法顯示對話框,並且返回 -1(如果您按 OK)和 0(如果您按 Cancel)。如果您已經使用了 msoFileDialogOpen 或 msoFileDialogSaveAs 枚舉值,您可以使用該類的 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 對象還提供了 GetOpenFileName 和 GetSaveAsFileName 方法,這些方法允許您選擇一個要打開的文件的文件名。儘管您可以使用這些方法,但是您將發現 Microsoft .NET Framework 提供的相對應的 OpenFileDialog 和 SaveFileDialog 控件功能更加豐富,而且更加易於使用。


其他有用的成員


Application 對象提供了一些不適用於其他種類的成員,例如 WorksheetFunction 屬性、Names 集合和 Windows 集合。下面幾部分將描述這些成員。


WorksheetFunction 類


Application 對象包含一個屬性 WorksheetFunction,這個屬性返回 WorksheetFunction 類的實例。這個類提供了許多共享/靜態方法,其中的每個方法都包裝了一個 Excel 工作表函數。這些方法中的每一個都公開許多 Excel 電子表格計算函數中的一個,而 VBA 沒有提供這些函數。而且其中的一些成員在 Visual Basic .NET 和 C# 的運算符和方法中已經具備,因此您不大可能會使用這些成員(例如,And 方法)。


您在 WorksheetFunction 類的方法中將會發現大量有趣的和有用的函數,總結在下面的列表中:


在 Visual Studio .NET 項目中,利用 WorksheetFunction 類非常容易。因爲項目模板爲您提供了 ThisApplication 對象,您可以簡單地引用該對象的 WorksheetFunction 屬性。示例應用程序包含一個名爲 Other Application Members 的工作表,如圖 4 所示,這個示例只測試了這個類的幾個成員。


注WorksheetFunction 類及其成員提供了一個好例子,說明了爲什麼從 Visual Basic 中使用 Excel 對象要比從 C# 中使用等效的代碼容易得多。WorksheetFunction 類的許多方法要求 C# 開發人員傳遞 30 個參數,其中的大多數爲空。當然,通過編寫封裝各種不同的方法組(一些具有一個必需的參數,一些具有兩個必需的參數,等等)的包裝無疑可以減輕這種負擔。 出於本文的目的,代碼調用&#8220;裸&#8221;方法,而不使用包裝方法。當然,C# 代碼很難看。


單擊 DemonstrateWorksheetFunction 鏈接運行下面的代碼(有關 Sort 方法的詳細信息,請參閱&#8220;對範圍內的數據進行排序&#8221;部分):

 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 都通過相似的範式使用顏色 &#8212; 每種都使用三個一組的字節,包含顏色中紅、綠和藍組成部分,編碼成 32 位整數的三個低位字節 &#8212; 但是它們處理顏色的方式不同。您可以使用 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 應用程序中的命名範圍。有許多檢索對命名範圍的引用的方法 &#8212; 您可以使用 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 類的各種屬性。下面的列表描述了一些最常用的成員:


單擊示例中的 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 &#8211; 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 類提供的所有其他方法之外,您還將發現有一大組事件可用。雖然不可能以任何一種一致的方式演示所有事件,但是單單根據名稱,就可以比較清楚地知道它們的用途。下面幾部分描述了這些事件的一個子集,並討論了在您自己的應用程序中最可能使用的事件。


提示 傳遞給 Office 應用程序中的事件處理程序的參數會讓人感到與用在本機 .NET 事件中的參數不同。通常,.NET 事件處理程序總是接收 Object 變量(該變量引用引發事件的對象)和第二個參數(該參數從 EventArgs 基類繼承而來,包含關於事件的額外信息)。沒有這樣定義良好的事件設計模式用於 Office 應用程序,因此每個事件處理程序都接受任意數目的參數(由最初的開發人員定義)。


錶行爲


Application 對象提供了各種與表(包括圖表和工作表)相關的事件。下面的列表包含關於許多這樣的事件的信息:


Window 行爲


Application 對象(和相應的 Workbook 對象)提供了各種處理 Window 對象的行爲的事件。下面的列表描述了這些事件:


Workbook 管理


Application 對象提供了各種當您與任何 Workbook 對象交互時都會發生的事件。這些事件過程中的每一個都接收 Workbook 變量,該變量指示參與事件的特定工作簿。下面的列表描述了可用事件的一個子集:



Workbook 類


正如您可能想象到的那樣,Workbook 類代表了 Excel 應用程序內的一個單一的工作簿。在這一部分,您將會了解這個類的一些成員,包括那些最常使用的屬性和方法。


提示 許多 Application 類的成員也作爲 Workbook 類的成員加以介紹。在這種情況下,其屬性適用於特定的工作簿,而不適用於活動工作簿。這一部分所要討論的成員遠比上一部分中討論的少,主要因爲您對許多提到的成員已經有所瞭解。


Workbook 類的屬性


Workbook 類提供了大量的屬性(大約 90 個),並且有許多屬性處理多數開發人員從不會考慮到的特殊情況;例如,AutoUpdateFrequency 屬性返回共享工作簿的自動更新的分鐘數;如果工作簿使用 1904 日期系統(一種日期順序方案,它將 1904 年 1 月 2 日作爲對應於值 1 的日期,通常使用於 Macintosh 計算機),Date1904 屬性會返回 True 值;PasswordEncryptionAlgorithm 屬性可以讓您設置用於加密密碼的確切算法,等等。


這一部分只是介紹您最可能用到的 Workbook 對象屬性,而不是試圖全面介紹其衆多屬性。通常的規則是:如果您需要工作簿的某一行爲,而其他人可能已經請求該行爲,實際上最可能的情況是一個屬性允許該行爲,而通常由一個方法提供該行爲。在您向一個工作簿中添加自己的代碼之前要仔細檢查文檔。


以下列表描述了一些最常使用的 Workbook 屬性:


使用 Document 屬性


正如其他的 Office 應用程序一樣,Excel 允許您在保存工作簿的同時保存文檔屬性。Excel 提供了許多內置屬性,並且您也可以添加自己的屬性。選擇&#8220;文件|屬性&#8221;來顯示如圖 7 所示的對話框,並且您也可以選擇&#8220;自定義&#8221;選項卡來創建和修改自定義屬性。



圖 7. 使用此對話框設置文檔屬性。



通過 Workbook 類的 BuiltInDocumentProperties 屬性來使用內置屬性,並通過 CustomDocumentProperties 屬性來使用自定義屬性。這些屬性都返回一個 DocumentProperties 對象,它是 DocumentProperty 對象的一個集合。通過集合內的名稱或者索引可以使用集合的 Item 屬性來檢索特定的屬性。在 Excel 文檔中有全部的屬性名列表,但是有一個檢索列表的簡單方法:當您單擊示例工作簿中的 Document Properties 鏈接時會運行下面的過程(參見 圖 8)。該過程調用 DumpPropertyCollection 方法列出所有內置屬性和它們的當前值,然後對自定義屬性也重複進行這一過程。此外,該過程還單獨修改 Revision Number 屬性,並且創建一個新的自定義屬性:

 Visual Basic
Private Sub DisplayDocumentProperties()
Dim prp As Office.DocumentProperty
Dim prps As Office.DocumentProperties
Dim rng As Excel.Range = _
ThisApplication.Range(DocumentProperties)
Dim i As Integer
Try
ThisApplication.ScreenUpdating = False
Try
prps = DirectCast( _
ThisWorkbook.BuiltinDocumentProperties, _
Office.DocumentProperties)
Set the Revision Number property:
prp = prps.Item(Revision Number)
prp.Value = CType(prp.Value, Integer) 1
Dump contents of the collection:
DumpPropertyCollection(prps, rng, i)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Work with custom properties:
Try
prps = DirectCast( _
ThisWorkbook.CustomDocumentProperties, _
Office.DocumentProperties)
DumpPropertyCollection(prps, rng, i)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Add a custom property:
Try
Delete the property, if it exists.
prp = prps.Item(Project Name)
prp.Delete()
Catch
Do nothing if you get an exception.
End Try
Try
Add a new property.
prp = prps.Add(Project Name, False, _
Office.MsoDocProperties.msoPropertyTypeString, _
White Papers)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Finally
ThisApplication.ScreenUpdating = True
End Try
End Sub
Private Sub DumpPropertyCollection( _
ByVal prps As Office.DocumentProperties, _
ByVal rng As Excel.Range, ByRef i As Integer)
Dim prp As Office.DocumentProperty
For Each prp In prps
rng.Offset(i, 0).Value = prp.Name
Try
If Not prp.Value Is Nothing Then
rng.Offset(i, 1).Value = _
prp.Value.ToString
End If
Catch
Do nothing at all.
End Try
i = 1
Next
End Sub
// C#
private void DisplayDocumentProperties()
{
Office.DocumentProperty prp = null;
Office.DocumentProperties prps =
(Office.DocumentProperties)
ThisWorkbook.BuiltinDocumentProperties;
Excel.Range rng = ThisApplication.
get_Range(DocumentProperties, Type.Missing);
int i = 0;
try
{
ThisApplication.ScreenUpdating = false;
try
{
// Set the Revision Number property:
prp = prps[Revision Number];
prp.Value = Convert.ToInt32(prp.Value) 1;
// Dump contents of the collection:
i = DumpPropertyCollection(prps, rng, i);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ThisApplication.Name);
}
// Work with custom properties:
try
{
prps = (Office.DocumentProperties)
ThisWorkbook.CustomDocumentProperties;
DumpPropertyCollection(prps, rng, i);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ThisApplication.Name);
}
// Add a custom property:
try
{
// Delete the property, if it exists.
prp = prps[Project Name];
prp.Delete();
}
catch
{
// Do nothing if you get an exception.
}
try
{
// Add a new property.
prp = prps.Add(Project Name, false,
Office.MsoDocProperties.msoPropertyTypeString,
White Papers, Type.Missing);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ThisApplication.Name);
}
}
finally
{
ThisApplication.ScreenUpdating = true;
}
}
private int DumpPropertyCollection(
Office.DocumentProperties prps, Excel.Range rng, int i)
{
foreach (Office.DocumentProperty prp in prps)
{
rng.get_Offset(i, 0).Value2 = prp.Name;
try
{
if (prp.Value != null )
{
rng.get_Offset(i, 1).Value2 =
prp.Value.ToString();
}
}
catch
{
// Do nothing at all.
}
i = 1;
}
return i;
}

提示 前面的代碼示例 DisplayDocumentProperties 使用了 Microsoft.Office.Core 程序集中的幾個枚舉和類型。示例代碼包含一個 Imports/using 語句,它將文本&#8220;Office&#8221;設置成這個命名空間的縮寫,就像設置&#8220;Excel&#8221;縮寫一樣。項目模板會自動設置&#8220;Excel&#8221;縮寫。而您需要自己添加&#8220;Office&#8221;語句。



圖 8. 內置的文檔屬性



注 儘管在這裏您使用的是 Excel 及其對象,但是實際上是 Office 提供了可用的內置文檔屬性列表,並且 Excel 沒必要實現所有的屬性 &#8212; 如果試圖訪問一個未定義屬性的 Value 屬性,就會觸發一個異常。示例過程包含應付這種情況(如果會出現的話)的簡單異常處理。


使用樣式


和 Word 文檔很相似,Excel 工作簿允許您將指定的樣式應用於工作簿內的區域,並且 Excel 提供了許多預定義的(儘管並不非常引人注目)樣式。使用&#8220;格式|樣式&#8221;菜單項,會顯示一個對話框,它允許您交互式地修改樣式,如圖 9 所示。



圖 9. 利用此對話框交互式地修改樣式。



單擊&#8220;樣式&#8221;對話框中的 Modify 會顯示&#8220;單元格格式&#8221;對話框,如圖 10 所示。



圖 10. 使用&#8220;單元格格式&#8221;對話框修改樣式。



&#8220;單元格格式&#8221;對話框顯示了您在格式化單元格時可以使用的所有選項,該對話框中可用的所有選項同樣可以在代碼中使用。您可以使用 Workbook 對象的 Styles 屬性來與工作簿交互,並對工作簿內的範圍應用樣式。


通過使用 Workbook 對象的 Styles 屬性,您可以創建、刪除和修改樣式。單擊示例工作簿中的 Apply Style 來運行以下過程,它創建了一個新的樣式(如果您已經運行了這段代碼,則使用已有的樣式),設置該樣式的各個方面,並將其應用到一個區域:

 Visual Basic
Private Sub ApplyStyle()
Const STYLE_NAME As String = PropertyBorder
Dim rng As Excel.Range
Get the range containing all the document properties.
rng = GetDocPropRange()
Dim sty As Excel.Style
Try
sty = ThisWorkbook.Styles(STYLE_NAME)
Catch
sty = ThisWorkbook.Styles.Add(STYLE_NAME)
End Try
sty.Font.Name = Verdana
sty.Font.Size = 12
sty.Font.Color = ColorTranslator.ToOle(Color.Blue)
sty.Interior.Color = ColorTranslator.ToOle(Color.LightGray)
sty.Interior.Pattern = XlPattern.xlPatternSolid
rng.Style = STYLE_NAME
rng.Columns.AutoFit()
End Sub
// C#
private void ApplyStyle()
{
const String STYLE_NAME = PropertyBorder;
// Get the range containing all the document properties.
Excel.Range rng = GetDocPropRange();
Excel.Style sty;
try
{
sty = ThisWorkbook.Styles[STYLE_NAME];
}
catch
{
sty = ThisWorkbook.Styles.Add(STYLE_NAME, Type.Missing);
}
sty.Font.Name = Verdana;
sty.Font.Size = 12;
sty.Font.Color = ColorTranslator.ToOle(Color.Blue);
sty.Interior.Color = ColorTranslator.ToOle(Color.LightGray);
sty.Interior.Pattern = Excel.XlPattern.xlPatternSolid;
rng.Style = STYLE_NAME;
rng.Columns.AutoFit();
}

GetDocPropRange 方法返回一個由文檔屬性填充的範圍。這個過程使用 Range.End 方法來查找由文檔屬性填充的範圍的結尾,並且基於這個範圍的左上角和右下角創建一個新的範圍:

 Visual Basic
Private Function GetDocPropRange() As Excel.Range
Dim rng As Excel.Range = _
ThisApplication.Range(DocumentProperties)
Dim rngStart As Excel.Range = _
DirectCast(rng.Cells(1, 1), Excel.Range)
Dim rngEnd As Excel.Range = _
rng.End(Excel.XlDirection.xlDown).Offset(0, 1)
Return ThisApplication.Range(rngStart, rngEnd)
End Function
// C#
private Excel.Range GetDocPropRange()
{
Excel.Range rng =
ThisApplication.get_Range(DocumentProperties, Type.Missing);
Excel.Range rngStart =
(Excel.Range) rng.Cells[1, 1];
Excel.Range rngEnd =
rng.get_End(Excel.XlDirection.xlDown).get_Offset(0, 1);
return ThisApplication.get_Range(rngStart, rngEnd);
}

提示 要想知道關於檢索和使用 Range 對象的更多信息,請參看本文後面標題爲&#8220;使用 Range&#8221;的章節。


一旦您運行了這段代碼,在示例工作簿中包含文檔屬性的區域會改變底紋和字體,如圖 11 所示。



圖 11. 應用自定義樣式之後



單擊 Clear Style 運行以下過程,它清除同一區域的樣式:

 Visual Basic
Private Sub ClearStyle()
Get the range containing all the document properties, and
clear the style.
GetDocPropRange().Style = Normal
End Sub
// C#
private void ClearStyle()
{
// Get the range containing all the document properties, and
// clear the style.
GetDocPropRange().Style = Normal;
}

使用表


Workbook 類提供了一個 Sheets 屬性,它返回一個 Sheets 對象。這個對象包含 Sheet 對象集合,其中每個對象既可以是 Worksheet 對象,也可以是 Chart 對象。單擊示例工作簿的 List Sheets 鏈接來運行下面的過程,它列出工作簿中的所有現有的表:

 Visual Basic
Private Sub ListSheets()
Dim sh As Excel.Worksheet
Dim rng As Excel.Range
Dim i As Integer
rng = ThisApplication.Range(Sheets)
For Each sh In ThisWorkbook.Sheets
rng.Offset(i, 0).Value = sh.Name
i = i 1
Next sh
End Sub
// C#
private void ListSheets()
{
int i = 0;
Excel.Range rng =
ThisApplication.get_Range(Sheets, Type.Missing);
foreach (Excel.Worksheet sh in ThisWorkbook.Sheets)
{
rng.get_Offset(i, 0).Value2 = sh.Name;
i = i 1;
}
}

您可能還會發現下面的 Sheets 類的成員會很有用。


Workbook 類的方法


Workbook 類提供了大量的方法,其中有許多方法處理一些非常特殊的情況。這一部分探討一些在每個應用程序中您都可能會用到的方法,而不是詳細介紹各種方法,並將一些難理解的方法放在後面的章節中介紹,下面的列表描述了一些您最可能使用的方法:



Worksheet 類


當您閱讀到文章的此處時,您已經瞭解了使用一個單獨的工作表需要掌握的大多數概念。儘管 Worksheet 類提供了大量的成員,但是其大多數的屬性、方法和事件與 Application 和(或) Workbook 類提供的成員是相同的或相似的。這一部分將集中探討 Worksheet 類的重要成員及特定問題,這些問題是您在本文的其他部分所沒有接觸過的內容。(您可以在示例工作簿中的 Worksheet Object 工作表看到這一部分中的例子。)


不存在 Sheet 類


儘管 Excel 提供了一個 Sheets 集合作爲 Workbook 對象的屬性,但是在 Excel 中您找不到 Sheet 類。相反,Sheets 集合的每個成員都是 Worksheet 或 Chart 對象。您可以以這種方式考慮它:把 Worksheet 和 Chart 類看成內部 Sheet 類的特定實例(並且對無法訪問源代碼的人來說,將無法知道這種看法是否和實際的實現相符),但是 Sheet 類對外部不可用。


使用保護


通常,Excel 中的保護功能可以防止用戶和(或)代碼修改工作表內的對象。一旦您啓用了對工作表保護功能,除非您預作安排,否則用戶不能編輯或者修改工作表。在用戶界面內,您可以使用 Tools|Protection|Protect Sheet 菜單項啓用保護功能。當選擇此項後會顯示&#8220;保護工作表&#8221;對話框,如圖 12 所示。您可以在此設置密碼或者允許用戶執行特定的操作。默認情況下,一旦啓用保護功能,所有的單元格都會被鎖定。此外,通過使用 Tools|Protection|Allow Users to Edit Ranges 菜單項(它會顯示如圖 13 所示的對話框),您可以讓用戶編輯特定區域。將這兩個對話框結合使用,您可以鎖定工作表,然後可以讓用戶編輯特定的功能和區域。



圖 12. 在用戶界面中,使用此對話框的控制保護。



a

圖 13. 使用此對話框,您可以允許用戶編輯特定的區域。



您可以使用工作表的 Protect 方法通過編程方法控制對工作表的保護。這個方法的語法如下面的例子所示,其中的每個參數都是可選的:

 Visual Basic
WorksheetObject.Protect(Password, DrawingObjects, Contents, _
Scenarios, UserInterfaceOnly, AllowFormattingCells, _
AllowFormattingColumns, AllowFormattingRows, _
AllowInsertingColumns, AllowInsertingRows, _
AllowInsertingHyperlinks, AllowDeletingColumns, _
AllowDeletingRows, AllowSorting, AllowFiltering, _
AllowUsingPivotTables)
// C#
WorksheetObject.Protect(Password, DrawingObjects, Contents,
Scenarios, UserInterfaceOnly, AllowFormattingCells,
AllowFormattingColumns, AllowFormattingRows,
AllowInsertingColumns, AllowInsertingRows,
AllowInsertingHyperlinks, AllowDeletingColumns,
AllowDeletingRows, AllowSorting, AllowFiltering,
AllowUsingPivotTables);

下面的列表描述了 Protect 方法的參數:


可以調用工作表的 Protect 方法來保護工作表,如下面的代碼片段所示,這段代碼設置了密碼,並且只允許排序:

 Visual Basic
DirectCast(ThisApplication.Sheets(1), Excel.Worksheet). _
Protect(MyPassword, AllowSorting:=True)
// C#
((Excel.Worksheet)ThisApplication.Sheets[1]).Protect(
MyPassword, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, true, Type.Missing, Type.Missing);

提示很明顯,在您的代碼中硬編碼密碼並不是一個很好的主意。最常見的情況是,您需要從用戶那裏得到密碼,然後將這個密碼應用於工作簿,但不保存。通常,在源代碼中您是不會看到硬編碼密碼的。


爲了取消對工作表的保護,您可以使用下面的代碼。這段代碼假定有一個名稱爲 GetPasswordFromUser 的過程,這個過程要求用戶輸入一個密碼,並且返回輸入的密碼值:

 Visual Basic
DirectCast(ThisApplication.Sheets(1), Excel.Worksheet). _
Unprotect(GetPasswordFromUser())
// C#
((Excel.Worksheet)ThisApplication.Sheets[1]).
Unprotect(GetPasswordFromUser());

Unprotect 方法將取消對工作表的保護,並讓您提供一個可選的密碼。


Excel 也提供其他兩個對象,您將會發現,當使用保護的時候它們很有用:Protection 和 AllowEditRange 對象。Protection 對象封裝了您調用 Protect 方法時指定的所有信息,及未保護區域的信息。通過調用 Protect 方法設置共享的 Protection 對象的屬性,這些對象提供了以下對應於 Protect 方法的參數的 Boolean 屬性:


此外,Protection 類提供 AllowEditRanges 屬性,它允許您指定工作表上的可編輯區域,對應於在圖 13 中所示的對話框中指定的信息。 AllowEditRanges 屬性包含一個 AllowEditRange 對象集合,其中的每個對象都提供許多有用的屬性,包括:


在示例工作簿上的 WorksheetObject 工作表(見圖 14)中,您可以試驗一下通過編程實現的保護功能。單擊 Protect 保護工作表,這樣您就只能編輯處於陰影區域的內容(名稱爲 Information 和 Date 的兩個範圍)。單擊 Unprotect取消保護工作表。



圖 14. 測試工作表的保護功能。



在示例工作表中的鏈接會運行以下過程:

 Visual Basic
Private Sub ProtectSheet()
Dim ws As Excel.Worksheet = _
DirectCast(ThisApplication.ActiveSheet, Excel.Worksheet)
With ws.Protection.AllowEditRanges
.Add(Information, ThisApplication.Range(Information))
.Add(Date, ThisApplication.Range(Date))
End With
ws.Protect()
End Sub
Private Sub UnprotectSheet()
Dim ws As Excel.Worksheet = _
DirectCast(ThisApplication.Sheets(Worksheet Class), _
Excel.Worksheet)
Unprotect the sheet.
ws.Unprotect()
Delete all protection ranges, just to clean up.
You must loop through this using the index,
backwards. This collection doesnt provide
an enumeration method, and it doesnt handle
being resized as youre looping in a nice way.
Dim i As Integer
With ws.Protection.AllowEditRanges
For i = .Count To 1 Step -1
.Item(i).Delete()
Next i
End With
End Sub
// C#
private void ProtectSheet()
{
Excel.Worksheet ws =
(Excel.Worksheet)ThisApplication.ActiveSheet;
Excel.AllowEditRanges ranges = ws.Protection.AllowEditRanges;
ranges.Add(Information,
ThisApplication.get_Range(Information, Type.Missing),
Type.Missing);
ranges.Add(Date,
ThisApplication.get_Range(Date, Type.Missing), Type.Missing);
ws.Protect(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);
}
private void UnprotectSheet()
{
Excel.Worksheet ws =
(Excel.Worksheet) ThisApplication.Sheets[Worksheet Class];
ws.Unprotect(Type.Missing);
// Delete all protection ranges, just to clean up.
// You must loop through this using the index,
// backwards. This collection doesnt provide
// an enumeration method, and it doesnt handle
// being resized as youre looping in a nice way.
Excel.AllowEditRanges ranges = ws.Protection.AllowEditRanges;
for (int i = ranges.Count; i >= 1; i--)
{
ranges[i].Delete();
}
}

對象屬性


Worksheet 類提供了幾個返回對象的屬性。下面的章節將介紹這些對象,並提供使用這些對象的例子。


批註


使用 Insert|Comment 菜單項,您可以在工作表的一個範圍中插入附加的文本批註(見圖 15)。在代碼中使用 Range 對象的 AddComment 方法也可以達到相同目的。下面的代碼刪除與名爲 Date 的範圍相關聯的批註(若存在批註),然後創建一個新的批註。最後,代碼通過調用下一個代碼示例所描述的 ShowOrHideComments 方法來顯示工作表中的所有批註(見圖 16):

 Visual Basic
Dim rng As Excel.Range = ThisApplication.Range(Date)
If Not rng.Comment Is Nothing Then
rng.Comment.Delete()
End If
rng.AddComment(Comment added & DateTime.Now)
Display all the comments:
ShowOrHideComments(Show:=True)
// C#
Excel.Range rng = ThisApplication.get_Range(Date, Type.Missing);
if (rng.Comment != null )
{
rng.Comment.Delete();
}
rng.AddComment(Comment added DateTime.Now);
// Display all the comments:
ShowOrHideComments(true);


圖 15. 在用戶界面中您可以方便地將一個新的批註插入到工作表中。




圖 16. 在示例工作表中顯示所有批註後



Worksheet 類提供了它的 Comments 屬性,這個屬性返回一個 Comments 對象。這個 Comment 對象集合允許您循環訪問和 Worksheet 相關的所有 Comment 對象。 Comment 類並沒有提供很多成員。可以使用 Comment 類的 Visible 屬性來顯示或者隱藏批註,或者使用 Delete 方法刪除批註。此外,您可能發現 Text 方法很有用:這個方法允許您將文本添加到批註中,可以添加到現有文本的後面,也可以覆蓋現有的文本。


添加一個批註後,您可能想要顯示工作表中的批註。示例項目包含一個過程 ShowOrHideComments,這個過程會顯示或者隱藏所有在活動工作表中的批註:

 Visual Basic
Private Sub ShowOrHideComments(ByVal Show As Boolean)
Show or hide all the comments:
Dim ws As Excel.Worksheet = _
DirectCast(ThisApplication.Sheets(Worksheet Class), _
Excel.Worksheet)
Dim i As Integer
For i = 1 To ws.Comments.Count
ws.Comments(i).Visible = Show
Next
End Sub
// C#
private void ShowOrHideComments(bool show)
{
// Show or hide all the comments:
Excel.Worksheet ws =
(Excel.Worksheet) ThisApplication.Sheets[Worksheet Class];
for (int i = 1; i <= ws.Comments.Count; i )
{
ws.Comments[i].Visible = show;
}
}

注 與 Excel 中的許多輔助集合類相似,Comments 集合沒有提供一個默認的枚舉器。也就是說,您將不能使用一個 For Each 循環來訪問這個集合的所有元素。對於類似 Comment 集合的集合,您必須使用一個索引的循環來循環訪問這個集合。


提綱


Excel通過使用提綱功能支持將不同行的數據進行分組。您也可以在代碼中利用相同的功能。例如,給定如圖 17 所示的一組行,您可以添加提綱功能(在所示的圖中已添加),這樣您就能夠將這些行進行摺疊(如圖 18 所示),摺疊的組如圖 19 所示。



圖 17. 創建這些組




圖 18. 摺疊的組




圖 19. 完全摺疊的組



Worksheet 類提供了 Outline 屬性,它本身就是一個 Outline 對象。 Outline 類並沒有提供太多成員,下面的列表描述了您可能會使用到的成員:


示 例工作表包含對應於 2001 (Data2001) 和 2002 (Data2001) 年及整個行集 (AllData) 的數據的命名範圍。這些命名範圍覆蓋工作表的整個範圍;要想進行分組,您必須使用包含所有行的範圍。對於 2003 的數據,沒有一個和其關聯的命名範圍以便示例代碼演示如何將所有的行作爲範圍使用。


創建組是很簡單的:可以調用與一個或多個完整行相對應的一個範圍的 Group 方法來創建組。(您可以指定 4 個可選的分組參數,包括:被分組的開始和終止值、按值分組和一個表明分組週期的 Boolean 值數組。該示例中沒有使用這些可選參數,因爲您很少會使用這些參數。)調用 Ungroup 方法可以取消分組。例如,單擊示例工作表上的 WorkwithGroups 鏈接來運行下面的代碼:

 Visual Basic
Private Sub WorkWithGroups()
Dim ws As Excel.Worksheet = _
DirectCast(ThisApplication.ActiveSheet, Excel.Worksheet)
Set worksheet-level features for the outline.
In this case, summary rows are below
the data rows (so Excel knows where to put
the summary rows), and we dont want Excel
to format the summary rows--thats already been done.
ws.Outline.SummaryRow = Excel.XlSummaryRow.xlSummaryBelow
ws.Outline.AutomaticStyles = False
Group the two named ranges. Each of these
ranges extends across entire rows.
ThisApplication.Range(Data2001).Group()
ThisApplication.Range(Data2002).Group()
ThisApplication.Range(AllData).Group()
The range of rows from 24 to 27 doesnt have
a named range, so you can work with that
range directly.
Dim rng As Excel.Range = _
DirectCast(ws.Rows(24:27), Excel.Range)
rng.Group()
Collapse to the second group level.
ws.Outline.ShowLevels(RowLevels:=2)
End Sub
// C#
private void WorkWithGroups()
{
Excel.Worksheet ws =
(Excel.Worksheet) ThisApplication.ActiveSheet;
// Set worksheet-level features for the outline.
// In this case, summary rows are below
// the data rows (so Excel knows where to put
// the summary rows), and we dont want Excel
// to format the summary rows--thats already been done.
ws.Outline.SummaryRow = Excel.XlSummaryRow.xlSummaryBelow;
ws.Outline.AutomaticStyles = false;
// Group the two named ranges. Each of these
// ranges extends across entire rows.
ThisApplication.get_Range(Data2001, Type.Missing).
Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
ThisApplication.get_Range(Data2002, Type.Missing).
Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
ThisApplication.get_Range(AllData, Type.Missing).
Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
// The range of rows from 24 to 27 doesnt have
// a named range, so you can work with that
// range directly.
Excel.Range rng = (Excel.Range)ws.Rows[24:27, Type.Missing];
rng.Group(Type.Missing, Type.Missing, Type.Missing,
Type.Missing);
// Collapse to the second group level.
ws.Outline.ShowLevels(2, Type.Missing);
}

爲了對三個命名範圍分組,代碼只是簡單的調用相應範圍的 Group 方法:

 Visual Basic
ThisApplication.Range(Data2001).Group()
// C#
ThisApplication.get_Range(Data2001, Type.Missing).
Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);

爲了對未命名的範圍分組,代碼使用了工作表的 Rows 屬性,給定行範圍。這個屬性返回一個對應於要使用的行的範圍:

 Visual Basic
Dim rng As Excel.Range = _
DirectCast(ws.Rows(24:27), Excel.Range)
rng.Group()
// C#
Excel.Range rng = (Excel.Range)ws.Rows[24:27, Type.Missing];
rng.Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);

單擊示例工作表中的 Clear Groups 鏈接來運行類似代碼,這樣可以清除組:

 Visual Basic
Private Sub ClearGroups()
Dim ws As Excel.Worksheet = _
DirectCast(ThisApplication.ActiveSheet, Excel.Worksheet)
Specify RowLevels and/or ColumnLevels parameters:
ws.Outline.ShowLevels(RowLevels:=3)
Dim rng As Excel.Range = _
DirectCast(ws.Rows(24:27), Excel.Range)
rng.Ungroup()
ThisApplication.Range(Data2001).Ungroup()
ThisApplication.Range(Data2002).Ungroup()
ThisApplication.Range(AllData).Ungroup()
End Sub
// C#
private void ClearGroups()
{
Excel.Worksheet ws =
(Excel.Worksheet) ThisWorkbook.Sheets[Worksheet Class];
// Specify RowLevels and/or ColumnLevels parameters:
ws.Outline.ShowLevels(3, Type.Missing);
Excel.Range rng = (Excel.Range) ws.Rows[24:27, Type.Missing];
rng.Ungroup();
ThisApplication.get_Range(Data2001, Type.Missing).Ungroup();
ThisApplication.get_Range(Data2002, Type.Missing).Ungroup();
ThisApplication.get_Range(AllData, Type.Missing).Ungroup();
}

通過使用這些方法,您可以創建和刪除組,並且可以控制工作表中顯示的組級。



Range 對象


Range 對象是您在 Excel 應用程序中最經常使用的對象;在您可以操作 Excel 內的任何區域之前,您需要將其表示爲一個 Range 對象,然後使用該 Range 對象的方法和屬性。Range 類是很重要的,目前爲止,本篇文章中的每個示例中在某種程度上都使用了一個 Range 對象。基本上來說,一個 Range 對象代表一個單元格、一行、一列、包含一個或者更多單元塊(可以是連續的單元格,也可以式不連續的單元格)的選定單元格,甚至是多個工作表上的一組單元格。


由於不可能討論 Range 這個大類的所有成員,所以這一部分集中探討三個主要的問題:


換句話說,由於 Range 對象在衆多不同場合下有衆多不同用途,所有本節集中回答&#8220;我如何......&#8221;這樣的問題,而不是提供對所有成員全面的列表。


管理選擇區域


儘管使用當前選擇區域作爲修改一個範圍的屬性和行爲的做法很具有吸引力,但是您最好避免這樣做。就像任何其他共享資源一樣,在 Excel 內的選擇區域代表用戶的選擇。如果您在代碼中修改該選擇區域,將會導致用戶失去對當前選擇區域的控制。經驗法則是:只有在您想改變用戶的選擇區域時,纔可以調用對象的 Select 方法。作爲一個開發人員,您不能只是爲了方便就去調用 Select 方法。如果您的目的只是設置一個範圍的屬性,總會有其他替代方法。總之,避免使用 Select 方法不但可以使您的代碼運行得更快,還可以使您的用戶免受干擾。


如下代碼清除用戶當前單元格相鄰區域,編寫這樣的代碼是很簡單的:

 Visual Basic
ThisApplication.ActiveCell.CurrentRegion.Select
DirectCast(ThisApplication.Selection, Excel.Range).ClearContents
// C#
ThisApplication.ActiveCell.CurrentRegion.Select();
((Excel.Range)ThisApplication.Selection).ClearContents();

這樣做會取消用戶的選擇。如果最初只選擇一個單元格,那麼當運行前面的代碼片段後,單元格附近的整大塊將會被選定。實際上,除非您的目的是選擇所有的單元格區域,否則使用如下所示代碼是更好的解決方案:

 Visual Basic
ThisApplication.ActiveCell.CurrentRegion.ClearContents
// C#
ThisApplication.ActiveCell.CurrentRegion.ClearContents();

爲什麼任何人都會想到使用第一個代碼片段呢?之所以會使用這樣的代碼,是因爲 Excel 開發人員在嘗試發現如何使用 Excel 內的各種對象及其方法的一開始都會傾向於使用 Excel 宏記錄器。這個一個好主意,但是宏記錄器編寫 的代碼實在很糟糕。通常,宏記錄器使用了選擇區域,並在記錄任何任務的時候修改選擇區域。


提示 當使用一個或一組單元格時,儘可能使用描述您想使用的單元格的範圍,而不是修改選擇區域。如果您的目的是更改用戶的選擇區域,則使用 Range.Select 方法。


在代碼中引用 Range


Range 類是很靈活的,您在編程使用範圍的時候會發現它給您提供太多的選擇。有時 Range 對象是單個的對象,而有時它代表對象的一個集合。它具有 Item 和 Count 成員,儘管 Range 對象通常指單個的對象,這使得有時如何準確使用 Range 對象成爲一件很棘手的事情。


提示 下面的幾個示例獲得一個範圍的 Address 屬性。這個屬性返回一個包含範圍座標的字符串,座標以下面幾種格式之一表示,包括:&#8220;$A$1&#8221;(單元格在位置 A1)、&#8220;$1&#8221;(在工作表的第一行)和&#8220;$A$1:$C$5&#8221;(範圍包括介於 A1 和 C5 之間矩形內的所有單元格)。&#8220;$&#8221;表示絕對座標(而非相對座標)。使用 Address 屬性是找到您要檢索的範圍的準確位置的最簡單方法。有關引用範圍的各種方法的更多信息,請參考 Excel 聯機幫助。


以其最簡單的方式,您可以編寫如下程序清單所示的代碼來使 Range 對象引用單個單元格或者一組單元格。所有示例都假定具有下面的設置代碼:

 Visual Basic
Dim ws As Excel.Worksheet = _
DirectCast(ThisWorkbook.Worksheets(1), Excel.Worksheet)
Dim rng, rng1, rng2 As Excel.Range
// C#
Excel.Worksheet ws = (Excel.Worksheet)ThisWorkbook.Worksheets[1];
Excel.Range rng, rng1, rng2;

您可以使用下面的任何一種方法來引用一個特定範圍(也有其他幾種取得 Range 對象引用的方法):


使用技術


開發人員通常要求具有這樣的能力:改變包含選定單元格的整行的字體,使文本變成粗體。Excel 中並沒有內置這個功能,但是添加它也不是非常困難。示例工作簿中的 Range 類的工作表包含一個特別處理的範圍:當您選擇一個條目,其所在行會變成粗體。圖 23 顯示了這一行爲。



圖 23. 選擇一個條目使整行變成粗體。



示例工作簿包含以下過程來處理格式化:

 Visual Basic
Private Sub BoldCurrentRow(ByVal ws As Excel.Worksheet)
Keep track of the previously bolded row.
Static intRow As Integer
Work with the current active cell.
Dim rngCell As Excel.Range = _
ThisApplication.ActiveCell
Bold the current row.
rngCell.EntireRow.Font.Bold = True
Make sure intRow isnt 0 (meaning that
this is your first pass through here).
If intRow <> 0 Then
If youre on a different
row than the last time through here,
make the old row not bold.
If rngCell.Row <> intRow Then
Dim rng As Excel.Range = _
DirectCast(ws.Rows(intRow), Excel.Range)
rng.EntireRow.Font.Bold = False
End If
End If
Store away the new row number
for next time.
intRow = rngCell.Row
End Sub
// C#
private int LastBoldedRow = 0;
private void BoldCurrentRow(Excel.Worksheet ws)
{
// Keep track of the previously bolded row.
// Work with the current active cell.
Excel.Range rngCell = ThisApplication.ActiveCell;
// Bold the current row.
rngCell.EntireRow.Font.Bold = true;
// Make sure intRow isnt 0 (meaning that
// this is your first pass through here).
if (LastBoldedRow != 0)
{
// If youre on a different
// row than the last time through here,
// make the old row not bold.
if (rngCell.Row != LastBoldedRow)
{
Excel.Range rng =
(Excel.Range)ws.Rows[LastBoldedRow, Type.Missing];
rng.Font.Bold = false;
}
}
// Store away the new row number
// for next time.
LastBoldedRow = rngCell.Row;
}

這個示例採用如下步驟來使當前行變成粗體,並且使前一次變成粗體的行變回原來的狀態:


示例工作簿從它的 SheetSelectionChange 事件處理程序調用 BoldCurrentRow 過程。在這個過程中,代碼驗證新選擇的行是否位於正確範圍(使用 Application 對象的 Intersect 方法),如果是,就調用 BoldCurrentRow 過程:

 Visual Basic
Private Sub ThisWorkbook_SheetSelectionChange( _
ByVal Sh As Object, ByVal Target As Excel.Range) _
Handles ThisWorkbook.SheetSelectionChange
If Not ThisApplication.Intersect(Target, _
ThisApplication.Range(BoldSelectedRow)) Is Nothing Then
The selection is within the range where youre making
the selected row bold.
BoldCurrentRow(DirectCast(Sh, Excel.Worksheet))
End If
End Sub
// C#
protected void ThisWorkbook_SheetSelectionChange(
System.Object sh, Excel.Range Target)
{
// Dont forget that the Intersect method requires
// thirty parameters.
if (ThisApplication.Intersect(Target,
ThisApplication.get_Range(BoldSelectedRow, 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)
!= null)
{
// The selection is within the range where youre making
//the selected row bold.
BoldCurrentRow((Excel.Worksheet) sh);
}
}

使用 Range


一旦您得到了對一個範圍的引用,您能用它作什麼呢?可以列出的用途是無窮的,只要您能夠想象得到。這一節集中討論一些使用 Range 對象的技術,並且爲每種技術提供簡單的示例。這一部分中的所有示例都可以在示例工作簿的 Range Class 工作表中找到。


自動填充範圍


Range 類的 AutoFill 方法允許您使用值自動填充一個範圍。大多數情況下,AutoFill 方法用於將遞增或遞減的值存儲到一個範圍中。您可以通過提供可選的常量來指定此方法的行爲。這個常量來自 XlAutoFillType 枚舉(xlFillDays、xlFillFormats、xlFillSeries、xlFillWeekdays、xlGrowthTrend、xlFillCopy、xlFillDefault、xlFillMonths、 xlFillValues、xlFillYears 或 xlLinearTrend)。如果您不指定一個填充類型,Excel 會假定您使用默認填充類型(xlFillDefault),並且填充它認爲合適的指定範圍。


示例工作表(如圖 24 所示)包含四個將被自動填充的區域。列 B 包含五個工作日;列 C 包含五個月;列 D 包含五年內逐年遞增的日期;列 E 包含一系列數字,每行以二遞增。圖 25 顯示運行示例代碼後的相同區域。



圖 24. 調用 AutoFill 方法之前的四個示例範圍。




圖 25. 自動填充範圍後。



單擊 AutoFill 鏈接運行以下過程:

 Visual Basic
Private Sub AutoFill()
Dim rng As Excel.Range = ThisApplication.Range(B1)
rng.AutoFill(ThisApplication.Range(B1:B5), _
Excel.XlAutoFillType.xlFillDays)
rng = ThisApplication.Range(C1)
rng.AutoFill(ThisApplication.Range(C1:C5), _
Excel.XlAutoFillType.xlFillMonths)
rng = ThisApplication.Range(D1)
rng.AutoFill(ThisApplication.Range(D1:D5), _
Excel.XlAutoFillType.xlFillYears)
rng = ThisApplication.Range(E1:E2)
rng.AutoFill(ThisApplication.Range(E1:E5), _
Excel.XlAutoFillType.xlFillSeries)
End Sub
// C#
private void AutoFill()
{
Excel.Range rng = ThisApplication.get_Range(B1, Type.Missing);
rng.AutoFill(ThisApplication.get_Range(B1:B5, Type.Missing),
Excel.XlAutoFillType.xlFillDays);
rng = ThisApplication.get_Range(C1, Type.Missing);
rng.AutoFill(ThisApplication.get_Range(C1:C5, Type.Missing),
Excel.XlAutoFillType.xlFillMonths);
rng = ThisApplication.get_Range(D1, Type.Missing);
rng.AutoFill(ThisApplication.get_Range(D1:D5, Type.Missing),
Excel.XlAutoFillType.xlFillYears);
rng = ThisApplication.get_Range(E1:E2, Type.Missing);
rng.AutoFill(ThisApplication.get_Range(E1:E5, Type.Missing),
Excel.XlAutoFillType.xlFillSeries);
}

每種情況您都必須指定兩個範圍:


AutoFill 方法的第二個參數(XlAutoFillType 枚舉值)是可選的。通常,您需要提供該值才能得到您想要的行爲。例如,嘗試改變以下代碼:

 Visual Basic
rng.AutoFill(ThisApplication.Range(D1:D5), _
Excel.XlAutoFillType.xlFillYears)
// C#
rng.AutoFill(ThisApplication.get_Range(D1:D5, Type.Missing),
Excel.XlAutoFillType.xlFillYears);
使之看起來像這樣:
Visual Basic
rng.AutoFill(ThisApplication.Range(D1:D5))
// C#
rng.AutoFill(ThisApplication.get_Range(D1:D5, Type.Missing),
Excel.XlAutoFillType.xlFillDefault);

代碼經過修改後,日期將按天遞增,而不是按年遞增。


在範圍中查找


Range 類的 Find 方法允許您在範圍內搜索文本。這個靈活的方法模仿 Excel 中的查找和替換對話框的行爲,如圖 26 所示 - 實際上,這個方法直接和這個對話框交互。也就是說,Range.Find 方法或者使用您傳遞給它的參數來決定它的搜索行爲,或者如果您沒有傳遞參數,它就使用其在查找和替換對話框中的值來進行查找。表 4 列出了 Range.Find 方法的參數,除了第一個參數外,其他所有參數都是可選的。



圖 26. 在這個對話框上的選擇會影響 Find 方法的行爲。



警告因爲 Range.Find 的 幾乎所有參數都是可選的,同時因爲用戶可能通過&#8220;查找和替換&#8221;對話框改變值,所以您要確保真正將所有值傳給了 Find 方法,除非您想將用戶的選擇也考慮在內。當然,C# 開發人員不需要擔心這個問題,因爲他們在每個方法調用時都必須提供所有參數。



以下示例來自示例工作簿,它搜索一個範圍(名稱爲&#8220;Fruits&#8221;),並更改含有單詞&#8220;apples&#8221;的單元格的字體(圖 27 顯示了搜索結果)。這個過程也使用了 FindNext 方法,它使用前面設好的搜索設置重複搜索。(Range.FindPrevious 方法和 Range.FindNext 方法的使用幾乎一樣,但這個示例沒用到。)您要指定在哪個單元格後搜索,而剩下的就由 FindNext 方法處理。



圖 27. 包含單詞&#8220;apples&#8221;的單元格的搜索結果



提示FindNext(和 FindPrevious)方法一旦搜索到範圍的末端,就會重新回到搜索範圍的開始位置。要確保搜索不會成爲無限循環,永遠不休,您需要在代碼中設定。示例過程演示了處理這種情況的一種方法。如果您想完全避免這種無限循環,或者您想進行一個比 Find/FindNext/FindPrevious 方法更加複雜的搜索,那麼您也可以使用一個 For Each 循環在一個範圍內對所有單元格進行循環查找。


單擊示例工作簿的 Range Class 工作表中的 Find 鏈接來運行以下過程:

 Visual Basic
Private Sub DemoFind()
Dim rng As Excel.Range = ThisApplication.Range(Fruits)
Dim rngFound As Excel.Range
Keep track of the first range you find.
Dim rngFoundFirst As Excel.Range
You should specify all these parameters
every time you call this method, since they
can be overriden in the user interface.
rngFound = rng.Find( _
apples, , _
Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart, _
Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext,
False)
While Not rngFound Is Nothing
If rngFoundFirst Is Nothing Then
rngFoundFirst = rngFound
ElseIf rngFound.Address = rngFoundFirst.Address Then
Exit While
End If
With rngFound.Font
.Color = ColorTranslator.ToOle(Color.Red)
.Bold = True
End With
rngFound = rng.FindNext(rngFound)
End While
End Sub
// C#
private void DemoFind()
{
Excel.Range rng = ThisApplication.
get_Range(Fruits, Type.Missing);
Excel.Range rngFound;
// Keep track of the first range you find.
Excel.Range rngFoundFirst = null;
// You should specify all these parameters
// every time you call this method, since they
// can be overriden in the user interface.
rngFound = rng.Find(apples, Type.Missing,
Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart,
Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext,
false, Type.Missing, Type.Missing);
while (rngFound != null)
{
if (rngFoundFirst == null )
{
rngFoundFirst = rngFound;
}
else if (GetAddress(rngFound) == GetAddress(rngFoundFirst))
{
break;
}
rngFound.Font.Color = ColorTranslator.ToOle(Color.Red);
rngFound.Font.Bold = true;
rngFound = rng.FindNext(rngFound);
}
}

這段代碼採取這些步驟來實現其目的:


單擊示例工作表的 Reset Find 鏈接來運行這個簡單的過程,開始運行時將會重新設置範圍:

 Visual Basic
Private Sub ResetFind()
Dim rng As Excel.Range = ThisApplication.Range(Fruits)
With rng.Font
.Color = ColorTranslator.ToOle(Color.Black)
.Bold = False
End With
End Sub
// C#
private void ResetFind()
{
Excel.Range rng = ThisApplication.
get_Range(Fruits, Type.Missing);
rng.Font.Color = ColorTranslator.ToOle(Color.Black);
rng.Font.Bold = false;
}

提示 如果您想在一個範圍內查找和替換,請使用 Range.Replace 方法。這個方法的使用類似於 Find 方法,但是可以讓您指定要替換的值。 Replace 方法返回一個指示是否執行替換的 Boolean 值。即使只替換一個值,它也會返回 True。


在範圍中對數據進行排序


就如通過 Excel 用戶界面對一個範圍內的數據進行排序一樣,您也可以採用編程方式使用 Range.Sort 方法對數據進行排序。您指出要被排序的範圍,要進行排序的至多三行或三列(可選),以及其他可選的參數,剩下的則由 Excel 來處理。表 5 列出了 Sort 方法的所有參數。(Visual Basic .NET 開發人員很可能只會用到其中的一部分,而 C# 開發人員則必須爲每個參數賦予值。)



提示當 調用像這樣的方法時,Visual Basic .NET 開發人員相對於 C# 開發人員來說,有着明顯的優勢。因爲您不太可能會用到所有參數,Visual Basic .NET 開發人員能夠使用命名的參數,只須指定他們需要的參數即可。而爲了接受默認行爲,C# 開發人員必須將所有不使用的參數傳遞 null 值。



圖 28. 您可以創建自己的自定義排序列表,然後在代碼中引用這些特定的排序順序。



單擊 Range Class 示例工作表中的 Sort 鏈接運行以下過程,它首先根據第一列中的數據來對&#8220;Fruits&#8221;範圍排序,然後根據第二列中的數據排序:

 Visual Basic
Private Sub DemoSort()
Dim rng As Excel.Range = ThisApplication.Range(Fruits)
rng.Sort( _
Key1:=rng.Columns(1), Order1:=Excel.XlSortOrder.xlAscending, _
Key2:=rng.Columns(2), Order2:=Excel.XlSortOrder.xlAscending, _
Orientation:=Excel.XlSortOrientation.xlSortColumns, _
Header:=Excel.XlYesNoGuess.xlNo)
End Sub
// C#
private void DemoSort()
{
Excel.Range rng = ThisApplication.
get_Range(Fruits, Type.Missing);
rng.Sort(rng.Columns[1, Type.Missing],
Excel.XlSortOrder.xlAscending,
rng.Columns[2, 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);
}

單擊同一個工作表中的 Reset Sort 鏈接來運行以下過程,它根據自定義排序方法對第二列進行排序,如圖 28 所示:

 Visual Basic
Private Sub ResetSort()
Dim rng As Excel.Range = ThisApplication.Range(Fruits)
rng.Sort(rng.Columns(2), OrderCustom:=6, _
Orientation:=Excel.XlSortOrientation.xlSortColumns, _
Header:=Excel.XlYesNoGuess.xlNo)
End Sub
// C#
private void ResetSort()
{
Excel.Range rng = ThisApplication.
get_Range(Fruits, Type.Missing);
rng.Sort(rng.Columns[2, Type.Missing],
Excel.XlSortOrder.xlAscending,
Type.Missing, Type.Missing, Excel.XlSortOrder.xlAscending,
Type.Missing, Excel.XlSortOrder.xlAscending,
Excel.XlYesNoGuess.xlNo, 6, Type.Missing,
Excel.XlSortOrientation.xlSortColumns,
Excel.XlSortMethod.xlPinYin,
Excel.XlSortDataOption.xlSortNormal,
Excel.XlSortDataOption.xlSortNormal,
Excel.XlSortDataOption.xlSortNormal);
}


下期內容


儘管本文看似冗長,但是它只是涉及到了由 Excel 對象模型提供的大量內容的表面而已。本文介紹了最重要的類 &#8212; Application、Workbook、Worksheet 和 Range &#8212; 但是沒有介紹其他可能對您有用的類。您也許需要研究由 Excel 對象模型提供的第二&#8220;層&#8221;類,例如,PivotTable 和 Chart 類。只要您肯費心尋找您需要的確切類,那麼 Excel 對象模型的完整性使得您可以完成任何您所要求的自動化任務。只要掌握本文的內容、Object Browser 和 Excel VBA 聯機幫助,您就應該能夠勝任在 Excel 中所能想象到的任何任務了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章