基于.net平台的office开发 (一)
-C#语言版
目录:
引言
使用Office对象模型
小结
引言:
过去的半年里,因为机缘一直在做基于.Net的office开发,主要Smart Document, Smart tag ,Research pane的开发。大大小小也完整了三个项目,有参与、有指导开发的。回顾起来,整个过程也是充满着辛苦和乐趣的。最近稍微闲适一点,就想把自己的所学记录下来,供后面的office开发者使用。由于过去有一段时间了,一时也不太好整理清楚自己的思路,我也就直接先从一点出发,然后再去回忆,可能写起来不一定有顺序,不过我想,等全部写完,读者可以自行去排循序。其中有些也参考了别人的代码,再此无法一一标出,只好对所有的前辈们,表示感谢。
使用Office对象模型
因为我们是基于office开发,所以肯定会用到office对象模型。但是上网查找一下,大部分的使用office对象模型的例子都是使用VBA或者VB开发的例子。而大家也知道VB的语法中。当你调用一个函数,你并不需要传入所有的参数,所以对于有些参数你可以直接的省略。而在C#中你需要对所有的参数都传入值,这点当时给我们带来了很大的麻烦。当时的时候我们就常常都是泡在MSDN的office对象模型中,下面我就给出几个我们开发过程中实际用到的例子。希望大家能够举一反三,有利于大家以后使用C#来做office开发。
问题1:创建一个Word对象?因为我们都是基于office的开发,所以我们实际上已经打开了一个Word文档,但是我们有的时候希望在此文档的基础上做修改。成为另外一个文档,但是又不会影响到当前这篇文档。那么这个时候我们就需要做两种想法。第一种想法,重新用编程的方法创建当前这个Word文档的对象,然后里面进行修改。显然,由于第一个需要请求写权限,而这个由于第一份Word已经打开,所以写权限已经被封锁。所以不可取,所以我们采取第二种策略,将当前文档保存一个临时文件,然后对这个临时文件进行编辑就可以。而这种保存临时文件的方法也有多种,比如说使用File.Copy,比如说使用两个FileStream的读出和读入操作来实现文件的拷贝。剩下的问题就是如何去打开这个文件。
首先我们当然去关注一下Word对象模型了,大家可以去看MSDN :
http://msdn.microsoft.com/library/en-us/vbawd11/html/wotocOMMap_HV01049667.asp
在这里面我只介绍对我们这个问题有用的部分。Word对象模型有如下一个层次Application->Documents,我认为Application就是表达当前我们这个Word进程。而Documents则是表示当前这个进程里所有打开的Word文档。那我们现在需要打开一个新的文档在里面进行自动化的程序的编辑,那么我们肯定需要不显示的打开这份临时文档。再关注一下Documents的方法:
http://msdn.microsoft.com/library/en-us/vbawd11/html/woobjDocuments1_HV05210589.asp 我们可以看到他有一个Open方法,可以返回一个Document对象。就是它了。可能有人会为那么我们的Application对象哪儿来呢?前面说过我们其实已经打开了一个Word文档,那么这个问题自然不用担心。对象视图中Open方法的定义如下:
public abstract new Word.Document Open ( System.Object FileName , System.Object ConfirmConversions , System.Object ReadOnly , System.Object AddToRecentFiles , System.Object PasswordDocument , System.Object PasswordTemplate , System.Object Revert , System.Object WritePasswordDocument , System.Object WritePasswordTemplate , System.Object Format , System.Object Encoding , System.Object Visible , System.Object OpenAndRepair , System.Object DocumentDirection , System.Object NoEncodingDialog , System.Object XMLTransform ),大家可以看到这里的很多都是object类型,而实际上他们都有自己对应的类型,这就需要我们去仔细察看MSDN中对于这个方法的介绍如下:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbawd11/html/womthOpen1_HV03076944.asp 我们可以发现其实很多的变量都是可选的,对于VB的编程来说我们直接不给这些对象传参数就可以了,而在C#中如果你不想传参数的话,你需要使用Type.Missing来代替。最终我们打开文档的代码如下:
object tt = (object)”C:\\temp001.doc”;
object tt2 = Type.Missing;
object tt8 = false;
Microsoft.Office.Interop.Word.Document tempDocument = ap.Documents.Open(ref tt,ref tt2,ref tt2,ref tt2,ref tt2,ref tt2,ref tt2,ref tt2,ref tt2,ref tt2,ref tt2,ref tt8,ref tt2,ref tt2,ref tt2,ref tt2);//ap就是一个Word的Application对象
大家可以看到其实需要传递的全部都是ref object 类型。而且大家可以看到倒数第5个参数传递的是false,表明当前的文档不被显示打开,也就是说不新弹出一个word界面。
问题2:如果在 Word中绘制表格。我们在Word里面希望通过程序的方法将一个对象数组中的值在Word中像一个表格一样的表现出来,代码如下
Word.Table tb1 = null;
Word.Range wdRangePara = null;
Word.Application wdApp = wdTarget.Application;//wdTarget是传入的一个Range对象
object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
try
{
wdRangePara = wdTarget.Paragraphs[1].Range;
//wdRangePara.InsertParagraphAfter();
wdRangePara.Collapse(ref oCollapseEnd);
object oTableBehavior = Word.WdDefaultTableBehavior.wdWord9TableBehavior;
object oAutoFitFixed = Word.WdAutoFitBehavior.wdAutoFitFixed;//设置一些表的行为和属性。
int h =0;
string testName = "";
for(int k = 0;k<studentExam.KeyPointName.Length;k++)
{
if(testName != studentExam.KeyPointName[k])
{
testName = studentExam.KeyPointName[k];
h++;
}
}//h表示我们需要绘制的行数,此处和数据源有关。
tb1 = wdApp.ActiveDocument.Tables.Add(wdRangePara,h+1,2,ref oTableBehavior,ref oAutoFitFixed);//行数是h+1,列数为2行,之所以加1因为第一行为列名
tb1.Cell(1,1).Range.Text = "KeyPoint name";//列名一
tb1.Cell(1,2).Range.Text = "KeyPoint Number";//列名二
for(int i = 1; i<=2;i++)
{
tb1.Cell(1,i).Range.Font.Bold = 1;//设置属性
}
string tempKeypointName = "";
int j = 0;
for(int i = 0 ;i< studentExam.KeyPointName.Length;i++)
{
if(tempKeypointName != studentExam.KeyPointName[i])
{
tempKeypointName = studentExam.KeyPointName[i];
tb1.Cell(j+2,1).Range.Text = studentExam.KeyPointName[i].ToString();
tb1.Cell(j+2,2).Range.Text = studentExam.KeyPointNum[i].ToString();
j++;
}//设定表的数据
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
问题三:如何在Excel中实现上述的Word中类似的表格功能。对于Excel本身就是一个表格的结构,所以实现起上面的问题要比Word简单的多,因为你只要记住你要实现的位置以及对应数据所要处于的位置,然后往相应的Cell中附值就可以了。使用的方法样例如下:
xlWS.get_Range("B6",Type.Missing).Value2 =”Good Example”;//xlWS是一个WorkSheet对象,由于当前我们本身就已经打开了Excel文档的基础上,所以我们很容易可以得到这个对象。
大家可以看到这个get_Range有两个参数,两个参数都是用来表示位置,如果你只写一个表示你设定的只是一个格子,如果你两个都设置了,而且不同,那么你将设定一个Excel的域,就是两个格子之间的域。一般此时就是一个表格了。
我们很显然可以使用上面的设置值的方法依次把我们需要现实的值设定到特定的表格中,说白了,就是给特定的位置附值罢了。
问题四:如何在Excel中绘制统计图形,大家都知道,在Excel中,如果我们选定了一定的包含数据的Cells我们就可以来生成相应的图形,比如柱状图,曲线图等等。现在我们希望这些动作都是程序帮助我们完成的,因为我们可能事先并不知道我们要绘制的统计图来自于那个数据域。显然我们还是和手动的方法采用相同的方式来实现,就是使用程序告诉Excel,我们要绘制什么样的图,我们的数据来源于那些域这些信息,然后让Excel去绘制图形。代码如下:
Excel.Application xlApp = wdTarget.Application;
Excel.Workbook wbk = xlApp.ActiveWorkbook;
Excel.Worksheet wks = null;
Excel.Range rngData = null;
Excel.Chart cht = null;
Excel.SeriesCollection sc = null;
Excel.Axis xlAxisCat = null;
Excel.Axis xlAxisVal = null;
xlApp.Cursor = Excel.XlMousePointer.xlWait;
xlApp.DisplayAlerts = false;
xlApp.ScreenUpdating = false;
wks = wdTarget.Worksheet;
wks = (Excel.Worksheet)wbk.Worksheets[num];
wks.Activate();
try
{
rngData = wks.get_Range(cell1,cell2);
string strCaption = Text;
cht = (Excel.Chart)wbk.Charts.Add(Type.Missing,Type.Missing,Type.Missing,Type.Missing);//新建一个Chart图表
cht.ChartType = Excel.XlChartType.xlLineMarkers;//图表的类型,这里有和我们在Excel界面手动选择相对应的所有图表类型,但是都是英文的,你需要去确定对应关系
cht.SetSourceData(rngData,Excel.XlRowCol.xlRows);//这里设定了数据域
cht.HasLegend = true;
cht.HasTitle = true;
cht.ChartTitle.Caption = strCaption;
xlAxisCat = (Excel.Axis)cht.Axes(Excel.XlAxisType.xlCategory,Excel.XlAxisGroup.xlPrimary);
xlAxisCat.HasTitle = false;
xlAxisCat.TickLabels.Alignment = (int) Excel.Constants.xlCenter;
xlAxisCat.TickLabels.Offset = 50;
xlAxisCat.TickLabels.ReadingOrder = (int) Excel.Constants.xlContext;
xlAxisCat.TickLabels.Orientation = Excel.XlTickLabelOrientation.xlTickLabelOrientationUpward;
//xlAxisCat.MaximumScale = 10;
//xlAxisCat.MinimumScale = 0;
xlAxisCat.TickLabels.AutoScaleFont = true;
xlAxisVal = (Excel.Axis) cht.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary);
xlAxisVal.HasTitle = false;
xlAxisVal.MaximumScale=10;
xlAxisVal.MinimumScale=0;
xlAxisVal.TickLabels.AutoScaleFont = true;
cht.Location(Excel.XlChartLocation.xlLocationAsObject, wks.Name);
int countNeed = wks.Shapes.Count;
countNeed = wks.Shapes.Item(1).Fill.ForeColor.RGB = 1002;
wks.Shapes.Item(index).Height = 115;
wks.Shapes.Item(index).Width = 300;
wks.Shapes.Item(index).Left = 600;
wks.Shapes.Item(index).Top = height;
//以上对于图表的设定大部分都是可以在Excel的图形化界面里面进行手动设定的,大家编写的时候可以一一对应的去写
}
catch(System.Exception ex)
{
MessageBox.Show (ex.Message);
}
finally
{
this.ReleaseMyComObject(rngData);
this.ReleaseMyComObject(cht);
this.ReleaseMyComObject(sc);
xlApp.Cursor = Excel.XlMousePointer.xlDefault;
xlApp.DisplayAlerts = true;
xlApp.ScreenUpdating = true;
}
其实大家在编程来控制Excel来绘图的时候可以参考Excel界面中添加图形的方法,届时只要去找对应关系就可以了。不管是图形样式还是数据各个方面都有参考意义。
小结:
之所以称为小结是因为这篇文章只是整个系列的开始,因为是在回忆,所以想到哪儿写到哪儿,还没有去涉及到Smart Document, Smart tag 以及Research pane的开发。本篇全文介绍了使用office对象模型的几个技巧。可以供大家以后开发之用。
浙公网安备 33010602011771号