使用工作表对象
Worksheet对象表示Excel工作簿中的工作表。Worksheet有一个Name属性,返回工作表的名称(例如“Sheet1”)。
工作表管理
Worksheet对象具有一个Index属性,它为工作表窗口左下角显示的选项卡式工作表选项卡中的工作表提供基于1的选项卡位置。您可以使用Move方法将工作表移动到不同的选项卡位置。 Move方法有两个可选参数:一个Before参数,您可以传递要移动工作表之前的工作表,以及一个After参数,您可以传递要移动的工作表之后的工作表。如果省略了两个可选参数,Excel将创建一个新的工作簿,并将工作表移动到新的工作簿。
也可以使用复制方法制作工作表的副本。像Move方法一样,它需要两个可选参数:一个Before和After参数,用于指定复制的工作表应该相对于其他工作表的位置。您可以指定Before或After,但不能同时指定两个参数。如果省略了两个可选参数,Excel将创建一个新的工作簿,并将工作表复制到新的工作簿。
要激活特定的工作表,请使用Activate方法。此方法通过将与工作表相关联的第一个窗口设置为活动窗口来激活工作表。它还选择与工作表对应的选项卡,并在活动窗口中显示该工作表。
相当于右键单击工作表选项卡,并从弹出菜单中选择“删除”由Delete方法提供。使用此方法时,Excel会显示一个警告对话框。您可以通过使用Application对象的DisplayAlerts属性来防止出现此警告对话框,该属性将在本章前面的“控制Excel显示的对话框和警报”一节中讨论。
您可以隐藏工作表,以便通过使用Visible属性完全不显示其选项卡。 Visible属性的类型为XlSheetVisibility,可以设置为xlSheetVisible,xlSheetHidden和xlSheetVeryHidden。最后一个值隐藏工作表,以便只能通过将Visible属性设置为xlSheetVisible来再次显示。将Visible属性设置为xlSheetHidden隐藏工作表,但用户仍然可以通过转到“格式”菜单并选择“Sheet”,然后单击“隐藏”来取消隐藏工作表。
有时,使用Visible属性隐藏工作表,以便该工作表可用于存储应用程序在用户不会看到的“临时”工作表中使用的其他数据。 VSTO的缓存数据功能提供了更好的方法,如第18章所述。它具有额外的好处,您可以在Excel电子表格中操作隐藏的数据,而无需启动Excel。这使您可以在服务器上预填充具有自定义数据的Excel工作表。
请注意,工作簿必须至少包含一个可见的工作表。所以当使用Delete方法和Visible属性时,你必须牢记这个限制。如果您的代码尝试隐藏或删除工作簿中的最后一个可见表单,则会抛出异常。
清单5-23说明了几个这些属性和方法的用法。
清单5-23 适用于工作表集合的VSTO定制
private void ThisWorkbook_Startup(object sender, EventArgs e) { Excel.Worksheet sheetA = this.Worksheets.Add( missing, missing, missing, missing) as Excel.Worksheet; sheetA.Name = "SheetA"; Excel.Worksheet sheetB = this.Worksheets.Add( missing, missing, missing, missing) as Excel.Worksheet; sheetB.Name = "SheetB"; Excel.Worksheet sheetC = this.Worksheets.Add( missing, missing, missing, missing) as Excel.Worksheet; sheetC.Name = "SheetC"; // Tab indexes string msg = "{0} is at tab index {1}"; MessageBox.Show(String.Format(msg, sheetA.Name, sheetA.Index)); MessageBox.Show(String.Format(msg, sheetB.Name, sheetB.Index)); MessageBox.Show(String.Format(msg, sheetC.Name, sheetC.Index)); sheetC.Move(sheetA, missing); MessageBox.Show("Moved SheetC in front of SheetA"); // Tab indexes MessageBox.Show(String.Format(msg, sheetA.Name, sheetA.Index)); MessageBox.Show(String.Format(msg, sheetB.Name, sheetB.Index)); MessageBox.Show(String.Format(msg, sheetC.Name, sheetC.Index)); sheetB.Copy(sheetA, missing); Excel.Worksheet sheetD = this.Worksheets.get_Item( sheetA.Index - 1) as Excel.Worksheet; ((Excel._Worksheet)sheetA).Activate(); MessageBox.Show(String.Format( "Copied SheetB to create {0} at tab index {1}", sheetD.Name, sheetD.Index)); sheetD.Delete(); sheetA.Visible = Excel.XlSheetVisibility.xlSheetHidden; MessageBox.Show("Deleted SheetD and hid SheetA."); }
使用名称
如前所述,您可以使用Workbook.Names在工作簿级别定义命名范围。您还可以通过使用与Worksheet对象关联的Names属性来定义范围到特定工作表的命名范围。 Names属性返回一个仅包含作用域到作业表的名称的Names集合。有关Names集合的更多信息,请参阅本章前面的“使用名称集合和名称对象”一节。
使用工作表自定义属性
您可以添加具有名称和值的自定义属性到工作表。自定义属性是将其他隐藏信息与不想放入单元格的工作表相关联的便捷方式。不同于与工作簿关联的文档属性,Excel用户界面中的任何位置都不显示自定义属性。工作表级别的自定义属性不具有文档属性对其值的256个字符的限制。您可以在工作表自定义属性中存储更大的数据块。
CustomProperties属性返回与工作表关联的自定义属性的集合。您可以使用CustomProperties集合的Add方法添加自定义属性,并为要创建的自定义属性的名称传递一个字符串,并为要与自定义属性关联的值传递一个对象。要获取特定的自定义属性,请使用CustomProperties.Item方法并传递要获取的属性的索引。不幸的是,Item方法只需要一个基于1的索引,而不是您添加的自定义属性的名称。因此,您必须遍历该集合并检查每个返回的CustomProperty对象的Name属性,以确定是否已找到所需的自定义属性。清单5-24显示了创建自定义属性,然后再次访问的示例。
清单5-24 访问自定义DocumentProperty对象的VSTO自定义
private void ThisWorkbook_Startup(object sender, EventArgs e) { Excel.Worksheet sheet = this.Worksheets.Add(missing, missing, missing, missing) as Excel.Worksheet; // Add a custom property Excel.CustomProperties props = sheet.CustomProperties; props.Add("myProperty", "Some random value"); props.Add("otherProperty", 1); // Now, enumerate the collection to find myProperty again. foreach (Excel.CustomProperty prop in props) { if (prop.Name == "myProperty") { MessageBox.Show(String.Format( "{0} property is set to {1}.", prop.Name, prop.Value)); break; } } }
如果您使用VSTO将代码与工作簿相关联,通常最好使用缓存数据而不是自定义属性。 缓存的数据功能可以将数据集和任何XML可序列化类型放入文档中的数据岛。 该数据岛也可以在服务器上访问而不启动Excel。 有关VSTO的缓存数据功能的更多信息,请参见第18章。
保护工作表
Protect方法保护工作表,使用户不能修改工作表。 当使用Protect方法保护工作表时,工作簿中的所有单元都将被自动锁定。 保护方法对应于图5-3所示的“保护工作表”对话框。 您可以通过选择工具>保护>保护页面访问该对话框。
图5-3 保护工作表对话框。
传递给Protect方法的一些可选参数精确地控制可以修改的内容,如表5-14所示。 许多这些选项对应于图5-3所示的检查列表。
表5-14 保护方法的可选参数
当工作表受保护时,您有两种排除某些范围的单元格被锁定的方法。 第一种方法是使用从Worksheet.Protection.AllowEdit-Ranges返回的AllowEditRanges集合来添加排除对象。 AllowEditRanges集合对应于允许用户编辑范围对话框,如图5-4所示。 您可以通过选择工具>保护>允许用户编辑范围来访问此对话框。
图5-4 允许用户编辑范围对话框
必须先使用AllowEditRanges集合进行排除,然后再使用Protect方法来保护工作表。 在保护工作表之后,在重新取消保护工作表之前,不能对AllowEditRanges集合进行任何更改。 以此方式进行排除,可以给出标题,并显示在“允许用户编辑范围”对话框中。 以这种方式从保护中排除的范围将从其Range.AllowEdit属性返回TRue。 清单5-25显示了一个VSTO自定义,它使用AllowEditRanges创建两个保护的排除,然后使用Protect方法保护工作表。
清单5-25 使用AllowEditRanges将禁止添加到保护的VSTO自定义
private void ThisWorkbook_Startup(object sender, EventArgs e) { Excel.Worksheet sheet = this.Worksheets.Add(missing, missing, missing, missing) as Excel.Worksheet; Excel.AllowEditRanges allowEdits = sheet.Protection. AllowEditRanges; allowEdits.Add("Editable Cell", sheet.get_Range("A1", missing), missing); sheet.Protect(missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing); Excel.Range protectedRange = sheet.get_Range("A2", missing); MessageBox.Show(String.Format( "A2's Locked is set to {0}", protectedRange.Locked)); MessageBox.Show(String.Format( "A2's AllowEdit is set to {0}", protectedRange.AllowEdit)); try { protectedRange.Value2 = "Should fail"; } catch (Exception ex) { MessageBox.Show(ex.Message); } try { allowEdits.Add("This should fail", sheet.get_Range("A2", missing), missing); } catch (Exception ex) { // You can't add to the AllowEditRanges collection // when the worksheet is protected MessageBox.Show(ex.Message); } Excel.Range allowEditRange = sheet.get_Range("A1", missing); MessageBox.Show(String.Format( "A1's Locked is set to {0}", allowEditRange.Locked)); MessageBox.Show(String.Format( "A1's AllowEdit is set to {0}", allowEditRange.AllowEdit)); allowEditRange.Value2 = "Should succeed"; }
当工作表被保护时,排除某些范围的单元格被锁定的第二种方法是使用Range.Locked属性。 以这种方式排除的单元格不会显示在“允许用户编辑范围”对话框中。 清单5-26显示了使用Range.Locked属性添加排除对保护。
清单5-26 使用Range.Locked添加排除对象的VSTO自定义
private void ThisWorkbook_Startup(object sender, EventArgs e) { Excel.Worksheet sheet = this.Worksheets.Add(missing, missing, missing, missing) as Excel.Worksheet; Excel.Range range1 = sheet.get_Range("A2", missing); range1.Locked = false; sheet.Protect(missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing); MessageBox.Show(String.Format( "A2's Locked is set to {0}", range1.Locked)); MessageBox.Show(String.Format( "A2's AllowEdit is set to {0}", range1.AllowEdit)); range1.Value2 = "Should succeed"; }
工作表受保护后,可以通过多个属性来检查文档的保护设置,并进一步修改保护选项,如表5-15所示。
表5-15 允许您检查并进一步修改文档保护的属性
使用OLEObjects
除了包含单元格,工作表还可以包含来自其他程序(如嵌入式Word文档)和ActiveX控件的嵌入对象。要使用这些对象,可以在Worksheet对象上使用OLEObjects方法。 OLEObjects方法接受一个可选的Index对象参数,您可以传递OLEObject的名称或集合中OLEObject的基于1的索引。 OLEObjects方法也可以作为一种访问OLEObjects集合的方式,这可能令人困惑。如果你传递一个字符串,它表示为一个名字或一个基于1的索引作为一个int,它返回指定的OLEObject。如果您传递它Type.Missing,它返回OLEObjects集合。
任何时候,将OLEObject添加到工作表中,Excel还包括从“工作表”对象中的“样式”属性返回的“形状”集合中的该对象。要获取OLEObject唯一的属性,可以使用Shape.OLEFormat属性。
可以编写将ActiveX控件添加到工作表中的C#代码,并通过将OLEObject.Object或Shape.OLEFormat.Object转换为适当的类型与它们进行交谈。您必须在C#项目中添加与要使用的ActiveX控件相关联的COM库的引用。这样做会导致Visual Studio生成一个互操作程序集并将其添加到您的项目中。或者,如果为COM库注册了主互操作程序集,Visual Studio将自动添加对预生成的主互操作程序集的引用。然后,您可以将OLEObject.Object或Shape.OLEFormat.Object转换为Visual Studio为与ActiveX控件相对应的COM库对象添加的正确类型。
VSTO使您能够将Windows Forms控件添加到工作表中,功能更强大,以.NET为中心的处理控件的方式。因此,我们不会在本书中更多地使用ActiveX控件。有关VSTO对Windows Forms控件的支持的更多信息,请参见第14章“在VSTO中使用Windows窗体”。
使用形状
Shapes属性返回Shape对象的Shapes集合集合。 Shape对象表示可以插入到Excel电子表格中的各种对象,包括图形,AutoShape,艺术字,嵌入对象或ActiveX控件或图片。
“形状”集合具有“Count”属性,用于确定“工作表”中有多少个形状。它还有一个Item方法,它采用基于1的索引来获取集合中的特定形状。您还可以使用foreach枚举Shapes集合。
“形状”集合上的几种方法可以添加可以表示为“形状”的各种对象。这些方法包括AddCallout,AddConnector,AddCurve,AddDiagram,AddLabel,AddLine,AddOLEObject,AddPicture,AddPolyline,AddShape,AddTextbox和AddTextEffect。
Shape对象具有将Shape置于工作表上的属性和方法。它还具有允许格式化和修改Shape对象的属性和方法。 Shape对象上的属性返回的一些对象如图3-20所示。
使用ChartObjects
在本书中,当引用工作簿中的工作表的图表时,我们使用了短语图表。图5-5显示了在插入新图表时显示的图表向导的最后一页。 Excel使您能够将图表插入新的图表,我们称之为图表单,并允许您将图表作为对象添加到工作表中。对象模型调用在表单中添加为对象的图表。
图5-5 图表向导的图表位置步骤
事情更复杂的是,图表表的对象模型中的对象是一个图表,但ChartObject也有一个返回图表的属性。 ChartObject具有自己的一组属性,用于控制工作表中图表的位置。但是,由ChartObject.Chart属性返回的Chart对象可以找到实际操作图表内容的属性和方法。
要使用ChartObjects,可以在Worksheet对象上使用ChartObjects方法。 ChartObjects方法接受类型对象的可选索引参数,您可以传递集合中ChartObject的名称或ChartObject的基于1的索引。 ChartObjects方法也可以作为获取ChartObjects集合的一种方式,这可能会令人困惑。如果您传递一个表示为名称或基于1的索引的字符串,则返回指定的ChartObject。如果您传递它Type.Missing,它返回ChartObjects集合。
要将ChartObject添加到工作表中,可以使用ChartObjects.Add方法,它将“左”,“顶”,“宽”和“高”作为点的双精度值。每当您将ChartObject添加到工作表中时,Excel也会在“工作表”对象中的“Shapes”属性返回的“Shapes”集合中包含该对象。
使用列表
Excel 2003引入了从一系列单元格创建列表的功能。只需选择一系列单元格,右键单击选择,然后选择创建列表。列表具有列标题和下拉选项,使用户可以轻松地对列表中的数据进行排序和应用过滤器。它有一个总计行,可以自动求和并对一列数据执行其他操作。它在列表底部有一个标有星号的插入行,允许用户向列表中添加其他行。图5-6显示了Excel中的列表示例。
图5-6 Excel中的列表
您可以使用ListObjects属性访问工作表中的列表。 ListObjects属性返回ListObjects集合。 ListObjects集合有一个Count属性来确定Worksheet中有多少列表。 它还有一个Item方法,它将一个基于索引的索引或列表对象的名称作为一个字符串来从集合中获取一个ListObject对象。 您还可以使用foreach枚举ListObjects集合。
表5-16显示了ListObject对象的一些最常用的属性。 您将在第17章“VSTO数据编程”中讨论VSTO对数据的支持的更多信息。
表5-16 ListObject的关键属性