总序
之前的一个项目要求对学生的Office文件进行自动批改,通过检查题干要求的完成情况来评分。在网上没有找到这方面比较系统的资料,而且有些有的网友提供的方法还存在一些问题,希望我的
整理能够抛砖引玉,帮助大家熟悉Office的文档模型。 本系列主要调用微软提供的主互程序操作集(名字比较拗口,其实也就是各种接口和类,主要区别以VBA)来实现Office文档的自动化操作,对这些了解的越多越感到类库的给力,用MSDN上的话说,是可以完成想象到的任何任务。
虽然名字叫深入,但作者毕竟水平有限,不足的地方还请大家尽情拍砖头哈。 而且本文只是努力在浩繁的类中提纲挈领,想要充分了解还是得去慢慢研读MSDN。编译环境VS2010,语言C#,测试office版本2003,2007,2010,还有些必不可少的是操作需要的dll,这个网上到处都是,我也会附在之后的Demo里。
按目前的计划会在近阶段推出Excel,Word,Powerpoint,OutLook 四个大专题。
Excel文档模型与开发实战
说明:本专题首先介绍excel中最主要的四个类模型,Application,WorkBook,WorkSheet,Range,然后介绍一些拓展的类,如Chart,PivotTable,并理清他们之间的关系,给出开发时的代码实例。
一.命名空间解惑
为了避免大家对命名空间和调用的类库产生迷惑,首先需要提到的是微软针对每个程序提供的命名空间都有两种,例如Microsoft.Office.Interop.Excel和Microsoft.Office.Tools.Excel。其中Microsoft.Office.Tools.Excel是对Microsoft.Office.Interop.Excel的拓展,它包含了以下几个内容:
1.Workbook、Worksheet 和 ChartSheet 宿主项。 (Microsoft.Office.Interop.Excel内容)
上面提到的名词后面的系列会慢慢讲到,我们本篇的内容以第1条为主,即介绍Microsoft.Office.Interop.Excel中的内容。
二.文档模型
与其他的应用程序不同,Excel中的数据是高度结构化的,因此其中的类的层次也显得更为有序,Excel中提供的类有上百个,在其中最重要的类有Application,WorkBook,WorkSheet,Range。他们提供了对Excel的基本操作,其对应Excel中模型如下:
Application:
顾名思义,Application是代表整个应用程序的类,它主要包括这个Excel实例中用户的数据,用户的选项。
WorkBook:
WorkBook代表了一个工作薄。包含工作薄的属性和方法。
WorkSheet:
WorkSheet不仅代表了一个WorkSheet,也可以代表一个图表。(而像图中的图表是不会显示在WorkSheets集合中的,这里面的原因后面解释)
Range:
Range是使用频度最高的对象,它代表了Excel中任意选定的单元格范围。他可以代表一行,一列,多个连续或者不连续的单元格,这些单元格甚至可以分布在不同的WorkSheet中。
以上几个类是理解Excel操作集的基础,这些对稍有Excel使用经验的人来说很好理解。接下来对这几个类的功能做具体的分析:
Plus.下面提到的部分方法名方法,属性名是自己翻译的,可能和标准的有些出入,详情可查询MSDN:
http://msdn.microsoft.com/zh-cn/library/ms262200(v=Office.11).aspx
三.Application类详解
Application类提供的成员主要包括以下几类:
1.在Excel中控制状态和显示的成员:
这里提供的是应用程序级的操作,控制Excel的状态和显示。
属性名 |
返回类型 |
说明 |
Cursor |
XlMousePointer |
获取或设置鼠标外观 |
EditDirectlyInCell |
Bool |
直接就地获取或设置编辑单元格的能力 |
FixedDecimal |
Bool |
是否使用FixedDecimalPlaces 确定小数位数 |
Interactive |
Bool |
确定或设置用户是否与Excel交互 |
MoveAfterReturn |
Bool |
回车键后是否移植下一格 |
MoveAfterReturnDirection |
xlDirection |
回车键后的移动方向 |
ScreenUpdating |
Bool |
是否在调用后自动刷新屏幕 |
SheetsInNewWorkbook |
Long |
获取或设置 Excel 自动放置在新的工作簿中的工作表的数目。 |
StandardFont |
String |
获取或设置 Excel 中默认字体的名称 |
StandardFontSize |
Long |
获取或设置 Excel 中默认字体的大小; |
DisplayAlerts |
Bool |
设置警告信息的默认值 |
DisplayFormulaBar |
Bool |
是否显示标准公示栏以编辑单元格 |
DisplayFullScreen |
Bool |
是否以全屏模式运行 |
{
ThisApplication.ScreenUpdating = false ;
// Do your work that updates the screen.
}
finally
{
ThisApplication.ScreenUpdating = true ;
}
·StandardFont属性 和StandardFontSize属性重启后生效
2.返回对象的成员
所有的成员都可以在Application里调用到,这里的成员比较简单,不做过多解释。
属性名 |
返回类型 |
说明 |
ActiveCell |
范围 |
返回对活动窗口(顶部的窗口)中当前活动单元格的引用。 |
ActiveChart |
图表 |
返回对当前活动的图表的引用。 |
ActiveSheet |
对象 |
返回对活动工作簿中的活动工作表的引用。 |
ActiveWindow |
窗口 |
返回对活动窗口(顶部的窗口)的引用;如果没有活动窗口,则不返回任何结果。 |
Charts |
工作表 |
返回 Sheet 对象(Chart 和 Worksheet 对象的父对象)的集合,这些对象包含对活动工作簿中的每个图表的引用。 |
Selection |
对象 |
返回应用程序中选中的对象。 |
Sheets |
工作表 |
返回 Sheet 对象的集合,这些对象包含对活动工作簿中每个工作表的引用。 |
Workbooks |
工作簿 |
返回 Workbook 对象的集合,这些对象包含对所有打开的工作簿的引用。 |
3.执行操作的成员
最常用的操作有重新计算和检查拼写
2 ThisWorkbook.Calculate();
3 // 重新计算制定区域
4 ThisApplication.get_Range( " A1 " , " B12 " ).Calculate();
5 // 一个检查是否拼写正确的函数
6 private void TestSpelling()
7 {
8 Excel.Range rng = ThisApplication.
9 get_Range( " CheckSpelling " , Type.Missing);
10
11 rng.get_Offset( 0 , 2 ).Value2 =
12 (ThisApplication.CheckSpelling(
13 rng.get_Offset( 0 , 1 ).Value2.ToString(),
14 Type.Missing, Type.Missing)
15 ? " Spelled correctly "
16 : " Spelled incorrectly " );
17 }
18
特别需要提到的是关闭,API提供有Quit,但是由于是COM组件,无法完整清除内存,下面是网友提供的完全退出的代码:
1 //完全释放Excel
3 {
4 if (myExcel != null )
5 {
6 int generation = 0 ;
7 myExcel.UserControl = false ;
8
9 // 如果您将 DisplayAlerts 属性设置为 False,则系统不会提示您保存任何未保存的数据。
10 // _xlApp.DisplayAlerts = false;
11
12 if (myWorkBook != null )
13 {
14 // 如果将 Workbook 的 Saved 属性设置为 True,则不管您有没有进行更改,Excel 都不会提示保存它
15 // _xlWorkbook.Saved = true;
16 try
17 {
18 /// /经过实验,这两句写不写都不会影响进程驻留。
19 /// /如果注释掉的话,即使用户手动从界面上关闭了本程序的Excel,也不会影响
20 // _xlWorkbook.Close(oMissing,oMissing,oMissing);
21 // _xlWorkbook = null;
22
23 }
24 catch
25 {
26 // 用户手动从界面上关闭了本程序的Excel窗口
27 }
28 }
29
30 // 即使用户手动从界面上关闭了,但是Excel.Exe进程仍然存在,用_xlApp.Quit()退出也不会出错,用垃圾回收彻底清除
31 myExcel.Quit();
32
33 // System.Runtime.InteropServices.Marshal.ReleaseComObject((object)_xlApp);
34
35 generation = System.GC.GetGeneration(myExcel);
36 myExcel = null ;
37
38 // 虽然用了_xlApp.Quit(),但由于是COM,并不能清除驻留在内存在的进程,每实例一次Excel则Excell进程多一个。
39 // 因此用垃圾回收,建议不要用进程的KILL()方法,否则可能会错杀无辜啊:)。
40 System.GC.Collect(generation);
41 }
42 }
4.处理文件操作的成员
这里提供的是允许Excel上下文内的文件系统的交互
1
3 ThisApplication.get_Range( " DefaultFilePath " , Type.Missing).
4 Value2 = ThisApplication.DefaultFilePath;
5
6 // FileDialog 属性:获取FileDialog对象以实现打开文件,保存文件,选择文件名等操作
7 // FileDialog 属性需要您通过传递给它一个 msoFileDialogType 枚举值来选择对话框的特定使用
8 // FileDialog 的show方法以显示对话框,返回-1:点击OK 0:点击取消,Execute方法以实际打开文件,SelectedItems返回选择的文件名
9 g = ThisApplication.get_FileDialog(
10 Office.MsoFileDialogType.msoFileDialogOpen);
11 dlg.Filters.Clear();
12 dlg.Filters.Add( " Excel Files " , " *.xls;*.xlw " , Type.Missing);
13 dlg.Filters.Add( " All Files " , " *.* " , Type.Missing);
14 if (dlg.Show() != 0 )
15 dlg.Execute();
16
17 dlg = ThisApplication.get_FileDialog(
18 Office.MsoFileDialogType.msoFileDialogFolderPicker);
19 if (dlg.Show() != 0 )
20 {
21 ThisApplication.get_Range( " FolderPickerResults " , Type.Missing).
22 Value2 = dlg.SelectedItems.Item( 1 );
23 }
5.其他
1)Application可以返回WorkBooks,WorkSheets集合,这些内容与后面的内容有重复,暂时先跳过去。
2)WorkSheetFuntion类里的属性就非常有用了,这里面储存着Excel中众多的函数,大概如下:
数学函数,例如 Acos、Acosh、Asin、Asinh、Cosh、Degrees、Ln、Log、Median、Max、Min、Mode、Radians 等等。
域函数,允许您对范围执行运算,例如 DAverage、DCount、DCountA、DGet、DMax、DMin、DProduct、DSum 等等。
逻辑函数,例如 IsErr、IsError、IsLogical、IsNA、IsNonText、IsNumber、IsText。
统计函数,例如 BetaDist、BinomDist、ChiTest、ChiInv、LogNormDist、NegBinomDist、Pearson、SumProduct、SumSq、TDist、TTest,Var、VarP 等等。
3)Windows集合里的Window类提供了对Excel窗体内的操作
代码
// Arrangr(): 设置窗体集合的显示方式,接受一个XlArrangeStyle枚举以控制显示风格
ThisApplication.Windows.Arrange(
Excel.XlArrangeStyle.xlArrangeStyleTiled,
Type.Missing, Type.Missing, Type.Missing);
// NewWindow():创建一个新窗口
ThisWorkbook.NewWindow();
// 控制Windows对象的外观和现实:颜色,标题,窗口特性,滚动行为
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 ;4) Names集合里的Name属性提供了对命名范围(Range范围)的管理
1
2 // 新增一个命名范围
3 Excel.Name nm;
4 nm = ThisApplication.Names.Add(
5 " NewName " , @" ='Other Application Members'!$A$6 " ,
6 Type.Missing, Type.Missing, Type.Missing,
7 Type.Missing, Type.Missing, Type.Missing,
8 Type.Missing, Type.Missing, Type.Missing);
9 // 在代码中引用该命名范围
10 ThisApplication.get_Range(
11 " NewName " , Type.Missing).Value2 = " Hello, World! " ;
12
13 // 命名范围中的常用属性:Name:命名范围的名称,RefersTo:命名范围的名称,Value:解析为范围的内容的命名范围的引用
14 Excel.Range rng = ThisApplication.get_Range( " Names " , Type.Missing);
15 for ( int i = 0 ; i <= ThisApplication.Names.Count - 1 ; i ++ )
16 {
17 nm = ThisApplication.Names.Item(i + 1 ,
18 Type.Missing, Type.Missing);
19 rng.get_Offset(i, 0 ).Value2 = nm.Name;
20 // Without the leading "'", these references
21 // get evaluated, rather than displayed directly.
22 rng.get_Offset(i, 1 ).Value2 = " ' " + nm.RefersTo.ToString();
23 rng.get_Offset(i, 2 ).Value2 = " ' " + nm.RefersToR1C1.ToString();
24 rng.get_Offset(i, 3 ).Value2 = nm.Value;
25 }5)Application中的事件
在C#中 控件事件都有清晰的格式,Office中的事件参数就杂乱无章了。事件主要包括WorkSheet的事件,Workbook的事件和Windows的事件,好在事件的名字简单易懂,不再做过多介绍,可以直接查询MSDN