[转载]Office文档模型深入---Excel文档模型与开发实战

总序

  之前的一个项目要求对学生的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内容)

     2.宿主控件,包括 Chart、ListObject、NamedRange 和 XmlMappedRange。有关更多信息,请参见宿主项和宿主控件概述。
     3.提供 Excel 解决方案中的智能标记功能的类型,包括 Action 和 SmartTag。

     4.不同的帮助器类型,如事件参数和委托。 

 

     上面提到的名词后面的系列会慢慢讲到,我们本篇的内容以第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

是否以全屏模式运行

      

    补充 ·其中比较重要的有ScreenUpdating,通常设置为false以避免频繁刷新带来的性能问题,不过这个属性不会自动设置回true,官方推荐如下格式:
try
{
    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.执行操作的成员

    最常用的操作有重新计算和检查拼写 

 1 //重新计算打开的单元格
 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(02).Value2 = 
12         (ThisApplication.CheckSpelling(
13     rng.get_Offset(01).Value2.ToString(), 
14         Type.Missing, Type.Missing) 
15     ? "Spelled correctly" 
16     : "Spelled incorrectly");
17 }
18 

 

      

        特别需要提到的是关闭,API提供有Quit,但是由于是COM组件,无法完整清除内存,下面是网友提供的完全退出的代码:

   1  //完全释放Excel

 2         public void CloseExcel(Excel.Application myExcel, Excel.Workbook myWorkBook)
 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 

 2 //DefaultFilePath 属性:获取或加载Excel用于保存和加载文件的路径
 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 = 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中众多的函数,大概如下:

 

  • 数学函数,例如 AcosAcoshAsinAsinhCoshDegreesLnLogMedianMaxMinModeRadians 等等。

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

  • 逻辑函数,例如 IsErrIsErrorIsLogicalIsNAIsNonTextIsNumberIsText

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

    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

一.Workbook类:

      虽然标题叫Workbook类,但严格来说这样是不正确的,通过查询MSDN上的命名空间我们可以发现 Workbook和Worksheet都只是接口,我们平常所调用的其实是WorkbookClass和WorksheetChass,叙述习惯,继续沿用,但希望大家能了解到这一点。

  Workbook对应于Excel中的工作薄,在这里我们可以实现对工作薄的几乎所有操作。WorkBook类提供有大约90多个属性,其中有不少开发人员没有必要理会,下面介绍下可能用到的的属性和其对应的操作。

 

0.打开Excel文档

  这一部分不属于Workbook内容,但COM组件引用很多地方与大家习惯不同,为方便大家尽快上手,先贴出些代码

 

 1 using Excel = Microsoft.Office.Interop.Excel;
 2 // ........
 3 //初始化应用程序
 4 Excel.Application xapp = new Microsoft.Office.Interop.Excel.Application();
 5 if (xapp == null)
 6 {
 7      Console.WriteLine("No Excel File");
 8      return;
 9 }
10 string FilePath = Environment.CurrentDirectory+ @"\ExcelFile\Demo1.xls";
11 
12 //初始化方法Workbook
13 Excel.Workbook xbook = xapp.Workbooks.Open(FilePath, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
14                     Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
15 
16 //获取其他WorkBook
17 Excel.WorkbookClass CurrentWorkBook=((Excel.WorkbookClass)xapp.Workbooks[1]);

 

     这里面可以看出来Workbook初始化时候参数非常多,达到十几个,而且C#不像VB一样可以留空参数,所以得使用反射中的Missing.Value。而且在最后一行中Workbooks[1] 其实代表的是第一个工作薄,在Office COM组件里,集合的索引都是从1开始的,否则会引发异常COMException。此外,没有调用COM组件的朋友会发现类库中各种属性返回的值几乎都是object类型,需要有强制的类型转换,这点刚开始不会很习惯。

            

1.文档属性(Name,FullName,Path)

  Name返回文件名,Path返回文件路径,FullName返回完整路径与文件名

1 Console.WriteLine("{0}:{1}","文件名",xbook.Name);
2 Console.WriteLine("{0}:{1}","文件完整路径",CurrentWorkBook.FullName);
3 Console.WriteLine("{0}:{1}","文件路径", CurrentWorkBook.Path);

 

2.样式(Style)

      Excel为大家提供了丰富多彩的样式,如下图所示:

  

  我们平常所见的数字类型,对齐格式,字体,边框,填充,保护都属于样式的范畴,在这里可以充分地自定义。WorkBook中提供对本工作薄中出现样式的索引,考虑到知识的连贯性,样式具体的讲解我们放到第三篇Range类中进行详细介绍,这里贴出来一段代码以作示范

 1             #region 样式
 2             //样式类型
 3             const String STYLE_NAME = "PropertyBorder";
 4             Excel.Range rng = xapp.get_Range(xapp.Cells[1,1],xapp.Cells[4,4]);
 5             Excel.Style TempStyle ;
 6             try
 7             {
 8                 TempStyle = CurrentWorkBook.Styles[STYLE_NAME];
 9             }
10             catch
11             {
12                 TempStyle = CurrentWorkBook.Styles.Add(STYLE_NAME, Type.Missing);
13             }
14             TempStyle.Font.Name = "Verdana";
15             TempStyle.Font.Size = 14;
16             TempStyle.Interior.Pattern = Excel.XlPattern.xlPatternSolid;
17             rng.Style = TempStyle;
18             #endregion

  上述代码将(1,1)到(4,4)单元格的样式设置为字体"Verdana", 字号14,并且设置了内部线条样式。

3.密码

  通过Password属性可以获取与设置密码,当设置密码后,HasPassword会做相应的改变,不过获取的Password值总是为********,想直接通过这个属性来做Excel密码破解工具的朋友得换个思路了。

1             #region 密码
2             if (!xbook.HasPassword)
3             {
4                 xbook.Password = "12345";
5             }
6             Console.WriteLine("{0}:{1}""密码", xbook.Password);
7             #endregion

 

4.其他属性

  在上面之外,有一些属性并不需要开发人员在意的,如AutoUpdateFrequency (工作薄自动更新的时间),Date1904 (是否采用1904日期系统),PasswordEncryptionAlgorithm (设置加密的具体算法),RevisionNumber(返回共享后的版本号,如果设置为私有的话,会返回0)。

   也有一些属性用于获取当前的对象,如ActiveChartActiveSheet,还有最常用的Sheets,用以返回当前Workbook的WorkSheet,稍后我们就开始Worksheet的内容。

5.方法

  其实在这里面,了解了属性,也就了解了一大半方法了,“最经常的是一个属性允许该行为,而由一个方法来提供该行为”(MSDN)。去除这些属性相关的方法外,还有些方法会经常用到的如下: 

       

  • Active() :激活一个工作薄,并且打开第一个工作表
  • Close():关闭工作薄,不过此方法没法真正的关闭工作薄。
  • Protect():调用此方法以保护工作薄,从而保护工作薄不能新增Worksheet,此方法可以选用参数来设置密码和是否保护工作薄结构(保护后不能移动工作薄),如果把保护工作表里的数据的话还需要针对工作表来进行保护。
  • UnProtect():与Potect( )相对应的,必然会有一个UnProtect()
  • Save(): 保存工作薄
  • SaveAs():另存工作薄,不过这个方法较Save()的参数明显复杂得多,有文件名,文件格式,密码,是否为本地等选项。
  • SaveCpoyAs():将工作表的一个副本保存到文件,这个方法在做备份时十分好用
  • SendMail():顾名思义,将本工作薄发出来,不过之前要设置一系列配置,后面计划有专题。 
 1             #region 方法
 2             //激活该工作薄
 3             CurrentWorkBook.Activate();
 4             //关闭该工作薄
 5             CurrentWorkBook.Close();
 6             //保护该工作薄
 7             CurrentWorkBook.Protect("password", Type.Missing, Type.Missing);
 8             //保存该工作薄
 9             CurrentWorkBook.Save();
10             CurrentWorkBook.SaveAs("C:\\MyWorkbook.xml", Excel.XlFileFormat.xlXMLSpreadsheet, Type.Missing,
11                     Type.Missing, Type.Missing, Type.Missing, Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
12             CurrentWorkBook.SaveCopyAs("C:\\MyWorkbook.bac");
13             #endregion

 

 

二.Worksheet类

     通过Workbook类,我们已经了解到Worksheet的大部分功能了,他们的属性大多是相同的,只是worksheet将工作簿中的属性限制在一个特定的工作表中。

1.WorkBook的sheets属性 

    我们先接着Workbook中刚才跳过去的sheets属性开始,Workbook为sheet属性提供了常用的操作,这些也是使用频率比较高的:

    1)Visible 

      通过Visible属性来设置工作表的可视状态,设定的范围为XlSheetVisibility 枚举值(XlSheetHiddenXlSheetVeryHiddenxlSheetVisible)其中XISheetHidden为用户可设置的隐藏,而XISheetVeryHidden为编程设置的隐藏,用户无法操作。

    2)Add(),Delete():

      Add方法用于新增worksheet,提供参数有四个,其中两个限制的表的位置(before,after),此外还有表的数目和表的类型(worksheet还是chart) 

      Delete方法功能简单,调用更简单,无参数 

      3)Copy(),Move():

      Copy方法提供一个表的副本并将其插入工作薄的指定位置,如果没有手动设置位置,Excel会创建一个新的Workbook来储存之。

      Move方法与Copy方法就像复制和剪切一样,其余相同 

     4)FillAcrossSheet()

      用这个方法将工作表内的一部分数据复制到另一个表中,可以设置的参数包括范围 (Range对象),是否复制数据和复制时的格式(XlFillWith枚举,可以设置全部复制还是只复制格式

或内容).

    5) PrintPreview(),PrintOut()

       PrintPreview()函数设定打印预览,可以通过参数来设置禁止更改页面格局。

      PrintOut直接调用打印,这个函数可以设置打印时的绝大多数参数,包括,打印的起始截止页码,副本数量,打印前是否预览,打印机名等

    6) Select()

       Select方法用于设置用户的选择,许多对象都有这个方法。

    相关代码示例:

 2             Excel.Worksheet CurrentWorksheet = (Excel.Worksheet)CurrentWorkBook.Sheets[1]; 
 3             #region Sheets操作
 4             //新增工作表
 5             CurrentWorkBook.Sheets.Add(Type.Missing, Type.Missing, 1, Type.Missing);
 6             //删除新获取的工作表
 7             Excel.Worksheet TodeleteWorksheet = (Excel.Worksheet)CurrentWorkBook.Sheets[3];
 8             TodeleteWorksheet.Delete();
 9             //复制工作表
10             CurrentWorksheet.Copy(32);
11             //复制工作表中数据到另一工作表
12             CurrentWorkBook.Sheets.FillAcrossSheets(rng, Excel.XlFillWith.xlFillWithAll);
13             //打印工作表
14             CurrentWorkBook.Sheets.PrintOut(Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
15             //设置工作表可见性
16             CurrentWorksheet.Visible = Excel.XlSheetVisibility.xlSheetVisible;
17             #endregion

 

 

 2.工作表的保护

  在Workbook中我们也提到了工作表的保护,不过那里的保护是针对工作薄的结构,以限制新增修改移动工作表。而WorkSheet的保护是针对具体单元格内数据的,Excel程序中支持保护的内容如下图

 

在程序里我们自然也可以做相关限定。

  WorkSheet的保护方法自带的参数有 有密码,保护范围和具体的保护内容。密码可以留空,保护内容与图中所列一一对照,以bool值传入。保护范围包括保护是否保护形状(DrawingObjects),是否保护内容(Contents), 是否保护方案(Scenarios),是否仅允许界面修改(UserInterfaceOnly),需要注意的是这个如果设置为true的话,是只能程序修改,设为false的话是都不能修改....后面Allow开头的就是各种限制

 2 void Protect(
 3     [In, Optional] object Password, 
 4     [In, Optional] object DrawingObjects, 
 5     [In, Optional] object Contents, 
 6     [In, Optional] object Scenarios, 
 7     [In, Optional] object UserInterfaceOnly, 
 8     [In, Optional] object AllowFormattingCells, 
 9     [In, Optional] object AllowFormattingColumns, 
10     [In, Optional] object AllowFormattingRows, 
11     [In, Optional] object AllowInsertingColumns, 
12     [In, Optional] object AllowInsertingRows, 
13     [In, Optional] object AllowInsertingHyperlinks, 
14     [In, Optional] object AllowDeletingColumns, 
15     [In, Optional] object AllowDeletingRows, 
16     [In, Optional] object AllowSorting, 
17     [In, Optional] object AllowFiltering, 
18     [In, Optional] object AllowUsingPivotTables
19 );

 

 与Protect相对应的,也必然有个UnProtect(),解除保护的方法比较简单,不再做介绍

 但是还没有结束,Excel又很温馨地为大家提供了Protection对象和 AllowEditRanges 对象,他们分别封装了调用保护方法时的设置的信息和允许编辑区域的信息。

 Protection中有各种Allow开头属性的bool值。AllowEditRanges对象包括了一个AllowEditRange对象集合,AllowEditRange对象包含了诸如Range,Title,Users等有用的数据

 

3. 批注

  批注可以在Excel中的指定区域提供文字描述信息。这个属性通常由Range来添加,WorkSheet自带用Comments属性用以返回Comment对象,可以实现对WorkSheet中各个批注的遍历

 2             if (rng.Comment != null)
 3             {
 4                 rng.Comment.Delete();
 5             }
 6             rng.AddComment("Comment added " + DateTime.Now);
 7 
 8              //遍历显示批注
 9             for (int i = 1; i <= CurrentWorksheet.Comments.Count; i++)
10             {
11                 CurrentWorksheet.Comments[i].Visible = true;
12             }

 

4.分组 

  Excel允许通过分组来合并数据,当然我们也可以在代码中使用这个功能,下面是Excel分组功能的一个简单的效果

 

 在这里面是一个二级的分组,我们现在来看下Excel为我们提供了什么属性:

  WorkSheet的Outline属性会返回一个Outline对象,这个对象相对简单,他主要用到四个成员,AutomaticStyles,SummaryColumn,SummaryRow,

ShowLevels 分别对应 是否应用自动样式,提纲列的位置,提纲行的位置,显示的等级。

      接下来我们需要 创建一个组,用以将几个Range对象合并 

 

1 
2             //建立分组
3             rng.Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
4             //显示折叠线
5             CurrentWorksheet.Outline.ShowLevels(3, Type.Missing);

 

 

WorkBook和WorkSheet的介绍告一段落,接下来会介绍最常用的类 Range 以及拓展的功能如图表,邮件,希望能够对大家有帮助。 

 

     Range是最常见的对象,他可以代表Excel文档中的一个单元格,一行(列)单元格,若干行(列)单元格,几个不相邻的单元格,甚至他还可以代表不同工作表中的单元格。Range同时也给我们提供了非常便利的操作,如自动填充,查找,排序等。本篇的内容可以分为两部分:获取Range选区,对Range选区的操作。 

一.获取Range选区

下面是我们本次实例需要操作的Excel文档:

 

在Excel中,可以用"$A$1"来表示一个单元格,其中$表示绝对地址,A1即代表第一行第一列。同样的,我们可以用"$A$1:%E%7"来表示实例中的数据区域,即为A1到E7区域。在API中,我们同样可以通过如下方式获取Range区域。 

2             Excel.Range Range1 = CurrentWorksheet.get_Range("A1:C5");
3             Console.WriteLine(Range1.Address.ToString()); 

 

 另外,在上面例子中我们省略掉了$(去掉$之后表示相对地址,不过在本处仍表示这个区域),而在通过Address属性获取到的地址属性里返回的仍是"$A$1:$C$5",也就是Address返回的始终是绝对地址。因此在判断用户选区时,地址字符串要注意加个绝对地址符号。

通过上面的代码我们可以简单的获取一个连续的区域,我们还可以通过Application类的ActiveCell属性来获取用户在当前Excel中的选中区域

2             Excel.Range Range2 = xapp.ActiveCell;

 

 除此之外,还存在有另一种获取特定选区的方法,第一步是直接通过WorkSheet的Cells属性获取目标选区的起点位置(需要注意的是在如下的调用方法中,第一个参数代表列,第二个代表行),不太符合习惯。

2             Excel.Range Range3 = (Excel.Range)CurrentWorksheet.Cells[15];

 

 在获取起点位置之后,可以通过该起点位置的Rows,Columns属性来获取更大的选区。

 上面介绍的都是连续选区的获取,针对不连续的选区就要使用Range的合并,

2             Excel.Range Rangr4 = xapp.Union(Range1, Range2,
3                 Type.Missing, Type.Missing, Type.Missing, Type.Missing,
4                 Type.Missing, Type.Missing, Type.Missing, Type.Missing,
5                 Type.Missing, Type.Missing, Type.Missing, Type.Missing,
6                 Type.Missing, Type.Missing, Type.Missing, Type.Missing,
7                 Type.Missing, Type.Missing, Type.Missing, Type.Missing,
8                 Type.Missing, Type.Missing, Type.Missing, Type.Missing,
9                 Type.Missing, Type.Missing, Type.Missing, Type.Missing);

 

 这样可以获取一个不连续的选区,那么这个选区的Address属性会返回什么呢?

 

在获取Range对象时,还有个非常强大的工具Offset属性,Offset属性可以帮助我们获取相对地址,这样使选区的获得更加灵活,Range同样是一个参数化的属性,我们只能通过get_Offset()属性来获取Offset对象,下面的代码展示了Offset应用的灵活

2             Excel.Range Range5 = (Excel.Range)CurrentWorksheet.Cells[11];
3             for (int i = 1; i <= 5; i++)
4             {
5                 Range5.get_Offset(i, 0).Value2 = i.ToString();
6             }

 

 通过上面的实例,会在以A1开始的一列中分别填入数字(此处的索引方式是 从0开始,第一个参数表示行,第二个参数表示列,与Excel中其他地方不同)。

Range还有一些其他的属性可以协助我们获取选区。如下代码所示:其中Get_End用于获取选区中的选区,Excel.XlDirection枚举用来表示区域方位。

2             Excel.Range rngLeft, rngRight, rngUp, rngDown;
3             rng = (Excel.Range)xapp.Selection;
4             rngRight = rng.get_End(Excel.XlDirection.xlToRight);    //获取选区右侧的一个单元格
5             rngLeft = rng.get_End(Excel.XlDirection.xlToLeft);      //获取选区左侧的一个单元格
6             rngUp = rng.get_End(Excel.XlDirection.xlUp);            //获取选区上方的一个单元格
7             rngDown = rng.get_End(Excel.XlDirection.xlDown);        //获取选区下方的一个单元格

   

  二.对Range选区的操作

  上一部分我们了解到了获取Range选区的几种方法,接下来我们看一下针对Range选区类的一些基础操作:

  1.格式化选区

   通过API可以轻易地更改选区内的文字属性,如加粗等,下面的例子是MSDN中实现excel里 给选中的选区加粗,取消选择后恢复的代码:

 1 
 2         private int LastBoldedRow = 0;
 3         private void BoldCurrentRow(Excel.Worksheet ws)
 4         {
 5             // Keep track of the previously bolded row.
 6 
 7             // Work with the current active cell.
 8             Excel.Range rngCell = ThisApplication.ActiveCell;
 9 
10             // Bold the current row.
11             rngCell.EntireRow.Font.Bold = true;
12 
13             // Make sure intRow isn't 0 (meaning that 
14             // this is your first pass through here).
15             if (LastBoldedRow != 0)
16             {
17                 // If you're on a different
18                 // row than the last time through here,
19                 // make the old row not bold.
20                 if (rngCell.Row != LastBoldedRow)
21                 {
22                     Excel.Range rng =
23                         (Excel.Range)ws.Rows[LastBoldedRow, Type.Missing];
24                     rng.Font.Bold = false;
25                 }
26             }
27             // Store away the new row number 
28             // for next time.
29             LastBoldedRow = rngCell.Row;
30         }

 

  其中通过以下几步来实现

  ThisApplication.ActiveCell 以获取当前选中的单元格,

      rngCell.EntireRow.Font.Bold = true;以实现对粗体的控制,

  rngCell.Row != LastBoldedRow 判定是否已经离开选区

  

  2.自动填充

  Range类允许通过AutoFill方法来实现自动填充功能,使用此功能可以讲一组递增或递减的量填入某个选区,填充的方式会作为一个参数被传入,这个参数是一个XLAutoFillType枚举:

 

枚举名描述
xlFillCopy 复制值和格式到新单元
xlFillDays 拓展复制星期的值和格式到目标单元
xlFillDefault Excel默认复制方式
xlFillFormats 复制格式到目标单元
xlFillMonths 拓展复制月份的值和格式到目标但愿
xlFillSeries 拓展复制系列值 (e.g., '1, 2' 被拓展为 '3, 4, 5')和格式到目标但愿
xlFillValues 复制值到目标但愿
xlFillWeekdays
拓展工作周的日期名的值和格式到目标单元
xlFillYears
拓展年份的值和格式到目标单元
xlGrowthTrend 增长拓展数据和格式到目标单元(如1 2 拓展 4 8 16)
xlLinearTrend 线性拓展数据和格式到目标单元(如1 2 拓展 3 4 5)

 

2             Excel.Range Range3 = ((Excel.Range)CurrentWorksheet.Cells[11]).Columns;
3             Range3.AutoFill(Range1,Excel.XlAutoFillType.XlFillCopy);

 

   上述代码实现了以Range3为基础在Range1中的拓展,拓展方式为复制。参数中的填充的起点和目标范围是必须提供的,填充方式留空的话会默认xlFillCopy

 

  3.查找

   查找方法默认是和查找对话框对应的

  

  Range.Find()需要的参数比较多,可以实现搜索界面中所需的绝大多数功能。

  

参数

类型

说明

What(必需)

对象

要查找的数据;可以是一个字符串或者任何 Excel 数据类型。

After

范围

您想从这个范围的后面开始搜索(在搜索中,不包括这个单元格);如果不指定单元格,则从范围的左上角开始搜索。

LookIn

XlFindLookin(xlValue、xlComments、xlFormulas)

要搜索的信息类型;不能用 Or 运算符组合查询。

LookAt

XlLookAt(xlWhole、xlPart)

确定搜索匹配所有单元格,还是部分单元格。

SearchOrder

XlSearchOrder(xlByRows、xlByColumns)

决定搜索顺序;xlByRows(默认值)将横向搜索,然后纵向搜索;xlByColumns 将纵向搜索,然后横向搜索。

SearchDirection

XlSearchDirection(xlNext、xlPrevious)

确定搜索的方向;默认值是 xlNext。

MatchCase

布尔值

确定搜索是否区分大小写。

MatchByte

布尔值

确定是否双字节字符只和双字节匹配 (True) 或者也可以和单字节字符匹配 (False);只有当您安装了对双字节支持时才适用。

   

 

   与Find()类似的,Range提供有FindNext(),FindPrevious()以实现 查找下一个 和查找上一个,这个方法会调用上一次的Find(),不过在使用的时候需要注意,这两个方法在查找到了页首(页尾)的时候会自动重头来过,如果不想死循环的话就得在代码中控制了。还有一种比较原始的方法可以实现查找--对Range中的Cell进行遍历,有需要的话这也是个好方法,接下来附一段查找的代码:

 2         private void DemoFind()
 3         {
 4             Excel.Range rng = xapp.
 5                 get_Range("Fruits", Type.Missing);
 6             Excel.Range rngFound;
 7 
 8             // Keep track of the first range you find.
 9             Excel.Range rngFoundFirst = null;
10 
11             // You should specify all these parameters
12             // every time you call this method, since they
13             // can be overriden in the user interface.
14             rngFound = rng.Find("apples", Type.Missing,
15                 Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart,
16                 Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext,
17                 false, Type.Missing, Type.Missing);
18             while (rngFound != null)
19             {
20                 if (rngFoundFirst == null)
21                 {
22                     rngFoundFirst = rngFound;
23                 }
24                 else if (GetAddress(rngFound) == GetAddress(rngFoundFirst))
25                 {
26                     break;
27                 }
28                 rngFound.Font.Color = ColorTranslator.ToOle(Color.Red);
29                 rngFound.Font.Bold = true;
30                 rngFound = rng.FindNext(rngFound);
31             }
32         }

 

   4.替换

  替换为Replace()方法,这个方法和Find()类似,只是多了一个替换内容的参数,其他都可参照Find()

  

  5.排序

  就像Excel应用程序中一样,我们编程实现对Excel中数据的排序,指出来要排序的范围和方式,剩下的Sort()会帮我们搞定

  

  

参数

类型

说明

Key1

Object(String 或 Range)

首要排序字段,可以是一个范围名称 (String),或是一个 Range 对象,确定了要排序的值。

Order1

XlSortOrder(xlAscending、xlDescending)

为 Key1 中指定的值决定排序顺序。

Key2

Object(String 或 Range)

第二个排序字段,排序透视表时无法使用。

Type

Object

当对透视表进行排序时,指定对哪些元素排序;对一个普通范围则没有影响。

Order2

XlSortOrder

为在 Key2 中指定的值决定排序顺序。

Key3

Object(String 或 Range)

第三个排序字段,不能使用于透视表。

Order3

XlSortOrder

为在 Key3 中指定的值决定排序顺序。

Header

XlYesNoGuess(xlGuess、xlNo、xlYes)

指定第一行是否包含头信息,默认值为 xlNo;如果想让 Excel 自己去推测,就指定为 xlGuess。

OrderCustom

Integer

为自定义排序顺序列表指定一个基于 1 的索引;如果不指定这个参数,则使用默认排序顺序。图 28 显示了一种创建自定义排序顺序的技术。对于这个例子,将这个参数指定为 6 将基于“fruits”自定义顺序进行排序。

MatchCase

Boolean

设置成 True 就会进行区分大小写的排序,设置成 False 则进行不区分大小写的排序;不能用于透视表。

Orientation

XlSortOrientation (xlSortRows, xlSortColumns)

排序方向。

SortMethod

XlSortMethod(xlStroke、xlPinYin)

指定排序方法;不能适用于所有语言(当前值只适用于对汉字进行排序,而不适用于对其他语言排序)。

DataOption1

XlSortDataOption (xlSortTextAsNumbers, xlSortNormal)

指定如何对 Key1 中指定的范围进行文本排序;不能用于透视表排序。

DataOption2

XlSortDataOption

指定如何对 Key2 中指定的范围进行文本排序;不能用于透视表排序。

DataOption3

XlSortDataOption

指定如何对 Key3 中指定的范围进行文本排序;不能用于透视表排序。

 

 

   如上述表格所示,现在能提供的排序条件只有三组,暂不能实现无限条件。排序顺序可以通过XlSortOrder枚举实现升序降序,是否包含列头等属性,是否忽略大小等也可以由参数来控制,除排序条件外可以实现对话框中的所有选项。

本篇实例:

/Files/shenyubao/ExcelDemo-3.rar 

 

  以上列举了Range中一些常见的方法,还有些方法因为不太常用不再一一介绍,MSDN中可以查到完整列表:http://msdn.microsoft.com/zh-cn/library/microsoft.office.interop.excel.range_members.aspx   

posted on 2012-01-21 22:05  Arrow.Lu  阅读(654)  评论(0)    收藏  举报