内 容 简 介 本书从初学者角度出发,详细介绍了使用C#语言进行VSTO开发需要掌握的知识。全书分为12章, 内容包括VSTO入门概述、C#语法基础、C#进阶技术、C#操作Excel对象、创建Office外接程序、自定义 Office功能区、自定义任务窗格、自定义工具栏,VSTO外接程序的部署分发、VSTO开发Office文档、 VSTO开发资源大全、C#与VB/VBA语言的差异对比。书中所有章节涉及的程序代码都给出了详细的注 释。本书可以让读者轻松熟悉Visual Studio开发环境,跨入C#编程的门槛,掌握VSTO开发的步骤。 本书可作为职场办公人员、高校理工科师生、Office专业开发人员自学用书,也可以作为Office编 程培训讲师的教学参考书。 本书封面贴有清华大学出版社防伪标签,无标签者不得销售。 版权所有,侵权必究。侵权举报电话:010-62782989 13701121933 图书在版编目(CIP)数据 VSTO开发入门教程 / 刘永富著. — 北京:清华大学出版社,2017 ISBN 978-7-302-45371-0 Ⅰ. ①V… Ⅱ. ①刘… Ⅲ. ①BASIC语言—程序设计—教材 Ⅳ. ①TP312.8 中国版本图书馆CIP数据核字(2016)第260921号 责任编辑:杨如林 秦 健 封面设计:李召霞 责任校对:胡伟民 责任印制:沈 露 出版发行:清华大学出版社 网  址:http://www.tup.com.cn,http://www.wqbook.com 地  址:北京清华大学学研大厦A座 邮  编:100084 社 总 机:010-62770175 邮  购:010-62786544 投稿与读者服务:010-62776969,c-service@tup.tsinghua.edu.cn 质 量 反 馈:010-62772015,zhiliang@tup.tsinghua.edu.cn 印 装 者:北京国马印刷厂 经  销:全国新华书店 开  本:186mm×240mm 印  张:15.25 字  数:372千字 版  次:2017年1月第1版   印  次:2017年1月第1次印刷 印  数:1~3500 定  价:45.00元 ————————————————————————————————————————————— 产品编号:071876-01 . 程序代码调试、错误处理 . 使用类 第一阶段:熟悉Visual Studio 编程环境 . 理解VSTO 的概念 . 安装Visual Studio . 熟悉解决方案和项目文件夹 第二阶段:熟悉C#语言 . 创建C#窗体应用程序、窗体与常用控件的使用 . C#语法基础(变量、控制语句、不同数据类型的转换等) 第三阶段:C#操作和控制Excel对象 . 熟悉Excel对象模型,Excel对象的常用属性、方法和事件 . 加强从VBA代码向C#代码迁移的能力 第四阶段:界面设计部分 . 定制功能区:使用功能区设计器或使用XML代码,理解 Custom UI机制 . 任务窗格:任务窗格中控件和用户控件的添加 . 创建文档自定义项,使用文档操作窗格 . 自定义工具栏 第五阶段:VSTO 项目分发与安装程序的制作 . 使用Advanced Installer 其他知识点 . 使用C#制作Excel自定义函数(UDF) . 创建Word 、PPT等组件的VSTO 项目 VSTO 课程学习路线图 本书内容 本书内容以VSTO 学习路线图为依据编排而成,全书共分12章。 第1章:VSTO 入门概述 本书介绍的是一项程序开发技术,因此首先要让读者安装必要的程序语言和开发环 境。然后讲述VSTO 开发的意义和任务,以及创建和调试C#解决方案的方法与步骤。 第2章:C#语法基础 本书以C#为开发语言,因此读者需要掌握一定程度的C#语法基础。该章介绍了变量的 声明和赋值、流程控制与类的使用。 第3章:C#进阶技术 该章讲述了C#窗体与控件的相关技术,以及像正则表达式、字典等高级对象的用法, 目的是让读者在开发过程中,能够熟练应用这些高级对象去处理实际问题。 第4章:C#操作Excel对象 前面3章讲述的是纯粹的C#语言,而从这一章开始,讲述如何使用C#操作和控制Office 对象,该章以Excel为例,介绍了Excel的应用程序、工作簿、工作表、单元格区域等对象 的成员。 第5章:创建Office外接程序 VSTO 开发的目的旨在创建Office 外接程序(即COM加载项)。该章介绍了COM 加载 项的工作原理和开发基本步骤。 第6章:自定义Office功能区,第7章:自定义任务窗格 第6章和第7章分别介绍了VSTO 开发的重点,一般来说,创建一个Office 外接程序,界 面定制是非常必要的,为此本书在这两章里详尽地介绍了功能区的自定义技术和自定义窗 格的设计方法。 第8章:自定义工具栏 Office 工具栏是Office 组件中很重要的一个界面对象,为此本书通过典型的实例,讲述 了工具栏和控件的自定义方法。 第9章:VSTO 外接程序的部署分发 VSTO 开发的成品,一般需要能够在其他计算机上正常使用,为此,该章介绍了使用 Advanced Installer软件来创建VSTO 项目的安装程序。 第10章:VSTO 开发Office文档 文档自定义开发是VSTO 另一类型的项目。该项目允许自定义文档,可以向文档中加 入C#控件,以及创建和控制文档窗格。 第11章:VSTO 开发资源大全 “工欲善其事,必先利其器”,为了能够驾轻就熟地进行VSTO 开发,还需要使用其 他一些工具的辅助,为此,该章介绍了典型工具的安装和使用技巧。 第12章:C#与VB/VBA语言的差异对比 考虑到很多读者是从VBA转过来的,对VBA的语法和对象模型更为熟悉,为了能够帮 助读者更快地从VBA转入VSTO ,该章列出了两种语言典型的语法差异。 本书特点 本书是目前市面上稀缺而Office 开发人员急需的、Office 和C#技巧完美融合的经典书 籍,为了让读者快速了解和熟悉VSTO ,本书第2~4章的C#代码都配备了对应的VBA代码, 可以让之前从事VBA开发的读者迅速学会VSTO 开发。同时本书配套资源中包括本书涉及 的所有项目的源文件,以便读者加以验证和核对。另外,本书配套资源中还有与VSTO 开 发相关的全部有声视频教程。 本书配套资源内容说明 本书配套资源包括VSTO 开发入门视频教程、本书所有示例程序、VSTO 开发资源大全 三大部分内容。关于本书配套资源,读者可访问http://vba.mahoupao.net/forum.php?mod=vie wthread&tid=2407&fromuid=1进行下载。 大分类文件名对应章节或描述 VSTO 概述.wmv 第1章 C#语法基础.wmv 第2章 类的创建和使用.wmv 2.12节 窗体和控件的设计技术.wmv 3.7节 VSTO 开发 入门视频教程 C#操作Excel对象.wmv 第4章 创建Office外接程序.wmv 第5章 使用Ribbon设计器自定义Office功能区.wmv 6.4节 使用XML自定义Office功能区.wmv 6.5节 自定义任务窗格的设计.wmv 第7章 VSTO 外接程序的打包.wmv 第9章 VSTO 开发Office文档-文档操作窗格.wmv 第10章 ConsoleApplication20160629 1.2.1节 ExcelAddIn20160514 6.4节 ExcelAddIn20160515 6.5节 ExcelAddIn20160516 7.2节 ExcelAddIn20160517 8.2.1节 示例程序 ExcelWorkbook20160519 10.3节 Solution20160705 1.4节 UDF20160521 4.9.1节 VSTOBOOK-C# 第2章 VSTOBOOK-VB 第2章 WindowsFormsApplication20160522 4.2节 WindowsFormsApplication20160523 3.4节 续表 大分类文件名对应章节或描述 WindowsFormsApplication20160524 3.5.4节 WindowsFormsApplication20160525 3.6节 WindowsFormsApplication20160526 3.7节 示例程序 WindowsFormsApplication20160527 3.7.9节 WindowsFormsApplication20160528 3.8节 WindowsFormsApplication20160606 2.2节 WindowsFormsApplication20160625 2.12节 WindowsFormsApplication20160629 1.2.2节 OfficeCommandbarDesigner20160709.rar 11.1 节 OfficeCommandbarViewer20160709.rar FaceIDs_V2_20160709.xls FaceIDs_V2_20160709.doc Office2010ControlIDs.rar 11.2 节 VSTO 开发imageMso7345.xlsm 资源大全OfficeCustomUIEditorSetup.msi RibbonXMLEditor20160709.rar ribbon回调函数大全.xlsm UseAPI.rar 3.8节 VBE2014_Setup_20160709 11.3 节 VisualStudioAddin2016Setup.exe 读者对象 ● 职场办公人员 ● 理工科类大学生、研究生 ● 编程爱好者 ● 培训机构的老师和学员 本书约定 书中述及的多级菜单和工具栏的图示中,鼠标单击的各级菜单或命令均放在中文方括 号之中,各级之间以斜杠隔开。例如【文件/打开】表示连续单击了“文件”菜单的“打 开”子菜单。 书中所有的VBA和C#代码段,代码左侧均有行号,这些行号只是为了便于讲解,并不 属于代码部分。 读者服务 为了方便本书内容答疑,读者朋友可加入VBA/VSTO 开发QQ群:61840693,也可 以在VBA/VSTO 论坛(http://vba.mahoupao.net/forum.php )发帖,还可以直接给作者发 Email:lyflyf715@sina.com。无论哪一种方式,作者将竭诚为您服务。 如果要进一步学习Office、VBA、VSTO 等学科的视频课程,读者可在51CTO 学院搜索 作者主讲的相关课程:http://edu.51cto.com/user/user_id-6673733.html。 致谢 感谢刘爱珍、儒道佛潘淳、西西老师、张杰、闻启学等朋友以及兄长刘永和在本书编 写过程中给予的无私帮助和鼓励。 本书在出版过程中,得到了清华大学出版社策划编辑秦健先生的大力支持和配合,在 此表示衷心感谢。另外,本书所有的编审、发行人员为本书的出版和发行付出了辛勤劳 动,在此一并致谢。 特别说明 本书编写时所用的VSTO 开发环境如下: ● 操作系统:Windows 7(32bit) ● Office:Office 2010完整版 ● Visual Studio:Visual Studio 2012 ● 开发语言:C# 读者可以根据自身条件适当调整。 另外,本书涉及的所有VSTO 示例,均以Excel 2010 为开发对象,对于其他Office 组件 的开发,过程非常类似,读者可以在Excel开发的基础上自行探索。 致读者 微软Office 套件称得上是全世界最成功的办公软件,拥有非常多的用户。它之所以受 到人们的青睐,有多方面的原因,但是以下几点是有目共睹的:一是功能完善而且强大; 二是容易操作,用户容易学会;三是具有强大的编程开发功能。 随着计算机的发展,以往的手工操作办公软件已经不能满足现代办公的需要,因此, VBA以及VSTO 开发和应用技术应运而生。本书在编写过程中,受到了众多Office 开发人 员的关注,他们殷切希望本书尽早出版。除了刘永富之外,参与本书编写的人员还有章晓 琳、马成林、钟卓成、李四桂、何明、段留柱、高大伟、肖云、谭信章、戴海东、朱辉、 徐鹏、祝磊、管洪洋、刘爱珍、王继成、汪龙、林兴龙、梁加成等。在编写过程中难免 会有漏洞,欢迎读者通过清华大学出版社网站(www.tup.com.cn )与我们联系,帮助我们 改正提高。 刘永富 2016年7月于北京 2.3.2 比较运算符 ·································30 2.3.3 多条件的与或非运算 ·····················30 2.4 不同类型的强制转换 ····················31 2.4.1 ToString ·····································31 2.4.2 Parse ·········································31 2.4.3 Convert ······································32 2.5 使用数组 ···································33 2.5.1 数组的声明和初始化 ·····················33 2.5.2 一维数组 ····································33 2.5.3 数组元素的遍历 ···························34 2.5.4 二维数组 ····································35 2.6 条件选择语句 ·····························37 2.6.1 三元运算符 ·································37 2.6.2 if语句 ········································38 2.6.3 switch语句 ··································39 2.7 循环语句 ···································40 2.7.1 while循环 ···································40 2.7.2 do循环 ·······································41 2.7.3 for循环 ······································42 2.7.4 foreach循环·································43 2.8 流程控制语句 ·····························43 2.8.1 break语句 ···································43 2.8.2 continue语句 ·······························44 2.8.3 goto语句 ····································44 2.8.4 return语句 ···································45 2.9 输出对话框(MessageBox) ··········46 2.9.1 MessageBox语法 ··························46 2.9.2 自定义对话框的按钮 ·····················47 2.9.3 自定义对话框的图标 ·····················48 2.9.4 自定义对话框默认按钮 ··················48 2.9.5 处理对话框的用户响应 ··················48 2.10 输入对话框(InputBox) ·············49 2.11 过程与函数 ······························50 2.11.1 过程与函数的定义 ······················50 2.11.2 过程与函数的调用 ······················51 2.12 类的创建和使用 ························52 2.12.1 非静态类 ··································52 2.12.2 静态类 ·····································54 2.13 using指令 ·································55 2.14 错误处理 ·································55 本章要点回顾····································56 第3章 C#进阶技术 ···················57 3.1 文件与文件夹操作 ·······················57 3.1.1 System.IO命名空间 ·······················57 3.1.2 文件与文件夹处理实例 ··················58 3.2 文本文件的读写 ··························59 3.3 数据库操作 ································60 3.4 使用资源文件 ·····························61 3.4.1 添加资源文件 ······························62 3.4.2 资源文件中的字符串 ·····················62 3.4.3 资源文件中的图像 ························63 3.5 使用正则表达式 ··························65 3.5.1 创建Regex对象 ····························65 3.5.2 元字符 ·······································65 3.5.3 正则表达式选项 ···························66 3.5.4 正则表达式方法 ···························67 3.5.5 正则表达式测试器 ························71 3.6 使用字典 ···································72 3.6.1 字典对象的创建 ···························72 3.6.2 根据键检索值 ······························73 3.6.3 遍历所有键名 ······························74 3.6.4 遍历所有值 ·································74 3.6.5 去除重复 ····································74 3.7 窗体设计技术 ·····························76 3.7.1 窗体的显示 ·································76 3.7.2 窗体的卸载 ·································77 3.7.3 窗体与控件的事件 ························78 3.7.4 使用窗体菜单 ······························82 3.7.5 使用工具栏 ·································85 3.7.6 使用右键菜单 ······························87 3.7.7 使用状态栏 ·································88 3.7.8 使用文件选择对话框 ·····················90 3.7.9 运行期间动态增删控件 ··················91 3.8 使用Windows API 函数 ··················94 3.8.1 窗口类名和句柄 ···························95 3.8.2 使用Spy++ ··································98 3.8.3 使用UseAPI ······························ 100 3.8.4 获取光标位置 ···························· 101 本章要点回顾·································· 101 第4章 C#操作Excel对象·········· 102 4.1 Excel对象模型概述 ···················· 102 4.1.1 Application对象 ·························· 103 4.1.2 Workbook 对象 ··························· 104 4.1.3 Worksheet 对象 ··························· 104 4.1.4 Range对象 ································ 105 4.1.5 Window 对象 ······························ 105 4.2 创建可以访问Excel对象的C#窗体 应用程序 ································· 105 4.2.1 添加Excel 2010对象引用 ·············· 105 4.2.2 添加Office 2010对象引用 ·············· 105 4.3 操作Application对象 ··················· 107 4.3.1 获取正在运行的Excel对象 ············ 107 4.3.2 创建新的Excel对象 ····················· 109 4.3.3 Application对象常用属性 ·············· 109 4.3.4 Application对象常用方法 ·············· 110 4.3.5 Application对象常用事件 ·············· 110 4.3.6 Application重要集合对象 ·············· 111 4.4 操作Workbook 对象···················· 112 4.4.1 Workbook 对象常用属性··············· 112 4.4.2 Workbook 对象常用方法··············· 113 4.4.3 Workbook 对象常用事件··············· 114 4.4.4 Workbook 重要集合对象··············· 114 4.5 操作Worksheet 对象 ···················· 115 4.5.1 Worksheet 对象常用属性 ··············· 115 4.5.2 Worksheet 对象常用方法 ··············· 116 4.5.3 Worksheet 对象常用事件 ··············· 117 4.6 操作Range对象 ························· 117 4.6.1 Range对象常用属性···················· 117 4.6.2 Range对象常用方法···················· 118 4.6.3 Range对象的遍历 ······················· 119 4.6.4 二维数组与Range数据交换··········· 120 4.6.5 一维数组与Range数据交换··········· 121 4.7 操作Commandbar对象 ················ 121 4.8 操作VBE工程 ·························· 123 4.8.1 引用VBIDE类型库 ······················ 123 4.8.2 允许对VBA工程访问 ·················· 123 4.8.3 操作VBE各级对象 ······················ 125 4.9 创建Excel自定义函数 ················· 125 4.9.1 使用C#创建类库 ························ 126 4.9.2 工作表中使用C#开发的自定义 公式 ········································ 129 4.9.3 VBA中调用C#开发的自定义公式 ··· 131 4.9.4 C#中调用C#开发的自定义公式 ······ 131 4.9.5 客户机使用C#制作的自定义函数 ·······132 本章要点回顾·································· 133 第5章创建Office外接程序······· 134 5.1 Office COM加载项简介 ··············· 134 5.2 认识Office COM加载项管理 对话框 ···································· 134 5.3 创建第一个Office外接程序项目 ····135 5.4 ThisAddin的启动事件和卸载事件 ··136 本章要点回顾··································137 第6章 自定义Office功能区 ·······138 6.1 CustomUI概述 ··························138 6.1.1 CustomUI的意义 ························140 6.1.2 CustomUI的作用范围 ··················140 6.1.3 手工定制Office界面 ····················140 6.2 CustomUI与XML ·······················141 6.2.1 XML语法规则 ···························141 6.2.2 描述Office界面的XML ·················142 6.2.3 使用Ribbon XML Editor ···············148 6.3 CustomUI元素详解 ····················149 6.3.1 选项卡(tab)元素 ·····················150 6.3.2 组(group)元素 ························151 6.3.3 控件(control)元素 ···················151 6.4 VSTO中使用功能区可视化 设计器 ····································154 6.4.1 为按钮指定回调过程 ···················156 6.4.2 Group中加入DialogBoxLauncher ·····157 6.5 使用XML进行CustomUI定制 ········159 本章要点回顾··································162 第7章 自定义任务窗格 ············163 7.1 任务窗格行为控制 ·····················163 7.2 VSTO外接程序项目中添加任务 窗格 ·······································164 7.2.1 创建Excel 2010外接程序 ··············165 7.2.2 添加用户控件 ····························165 7.2.3 静态类中声明任务窗格对象 ··········166 7.2.4 创建并显示任务窗格 ···················167 7.3 功能区与任务窗格的交互控制 ······169 7.3.1 利用功能区切换按钮控制任务窗格的 显示隐藏 ··································169 7.3.2 处理自定义任务窗格事件 ·············172 7.3.3 完全卸载任务窗格 ······················173 本章要点回顾··································173 第8章 自定义工具栏 ···············174 8.1 Office工具栏对象简述 ················174 8.1.1 Commandbar对象 ·······················174 8.1.2 CommandbarControl对象 ··············175 8.1.3 自定义工具栏的作用和意义 ··········176 8.2 VSTO实现自定义工具栏 ·············176 8.2.1 创建自定义工具栏 ······················176 8.2.2 处理工具栏按钮的回调 ················178 8.2.3 修改右键菜单 ····························179 8.2.4 卸载外接程序时清除自定义 ··········180 本章要点回顾··································181 第9章 VSTO外接程序的部署分发 ···182 9.1 客户机搭建VSTO运行环境 ··········182 9.2 VSTO外接程序的简单安装 ··········183 9.3 使用Advanced Installer ················184 9.3.1 创建aip安装包工程 ·····················184 9.3.2 客户机运行安装包 ······················193 本章要点回顾··································194 第10章 VSTO开发Office文档 ···195 10.1 文档自定义项编程概述 ·············195 10.2 文档自定义项允许添加的界面 元素 ·····································195 10.3 创建Office文档项目 ··················196 10.3.1 文档上添加C#控件 ····················198 10.3.2 文档项目的启动事件过程 ···········198 10.4 文档操作窗格概述 ···················199 10.5 文档操作窗格综合实例 ·············200 10.5.1 添加用户控件到文档窗格 ···········202 10.5.2 添加多个相同控件到文档窗格 ·····204 10.5.3 使用代码创建窗体控件并添加到 文档操作窗格 ··························205 10.5.4 定制功能区按钮控制文档操作 窗格 ······································206 10.6 文档自定义项的部署分发 ··········210 本章要点回顾··································211 第11章 VSTO开发资源大全 ·····212 11.1 Office 2003以下版本工具栏和控件的 自定义 ··································212 11.1.1 OfficeCommandbarDesigner ··········212 11.1.2 OfficeCommandbarViewer ············213 11.1.3 FaceIDViewer ···························213 11.2 Office 2007以上版本功能区的 自定义 ··································215 11.2.1 Office2010ControlIDs ·················215 11.2.2 imageMso7345 ··························216 11.2.3 OfficeCustomUIEditor ·················217 11.2.4 Ribbon XML Editor ····················217 11.2.5 Ribbon回调函数大全 ··················217 11.3 编程环境辅助工具 ···················218 11.3.1 VBE2014 ································219 11.3.2 VisualStudioAddin2016 ···············220 第12章 C#与VB/VBA语言的差异 对比··························222 12.1 变量必须声明 ·························222 12.2 严格的类型匹配 ······················222 12.3 项目的自动保存 ······················222 12.4 严格区分大小写 ······················223 12.5 语句结束必须加分号 ················223 12.6 语句块 ··································223 12.7 调用其他函数圆括号不能少 ·······224 12.8 数组的下标为0 ························224 12.9 数组或集合对象的索引使用 方括号 ··································225 1. 更安全C托管代码扩展 VSTO 允许托管和非托管代码一起无缝地放在相同的.NET程序集里,这允许开发者保 留非托管代码而无须完全重写。带有链接或引用托管代码程序集的文档或工作簿被作为托 管代码扩展。通过使用VSTO 在Word 或Excel中创建托管代码扩展,与宏相似但更安全。使 用VSTO 能够创建仅需要装载数据的模板。 2. 自定义功能 使用可重复使用的类,VSTO 3.0 提供极好的控制来自定义Office 应用程序。不像VBA 开发者,VSTO 开发者不局限于VBA函数库。VSTO 提供了相当广泛的类、对象和事件来创 建Office 商业解决方案。使用VSTO ,开发者能够为Office 应用程序自定义功能。这能够简 单到在应用程序命令栏中添加按钮或自定义任务窗格,或者复杂到用于访问不同数据源的 数据报表模板。 3. 自定义用户界面 VSTO 提供Windows 窗体控件,帮助你为Office 解决方案开发富用户界面(UI)。通过 使用大量各种各样的控件集,VSTO 开发者能够为用户创建丰富的数据视图。每种和每类 Windows 窗体控件都有自己的属性、方法和事件设置,适合不同的需要。 通过在文档和任务窗格里使用控件,VSTO 使创建丰富的用户界面更容易。例如,可 以创建一个活泼的按钮命令产生套用信函。又如,假设公司在其服务器上存储了数据内 容,用户在处理文档时想从服务器中引用一些内容并且不想离开当前编辑的文档,使用 VSTO 可以使服务器内容在文档的任务窗格中可用而无须干扰用户当前的工作。 4. WPF支持 WPF能用于创建丰富的、具有吸引力的外观。在VSTO 环境中可使用WPF。VSTO 的可 视设计器支持Windows 窗体和WPF控件的使用。WPF为创建基于客户和基于网络的应用程 序提供了可靠的编程模型,并且在商务逻辑和UI之间呈现清楚的分离。 5. 可视化C设计器 VSTO 为Office应用程序提供了可视化的设计器,例如Word 2007 、Excel 2007 ,显示在 Visual Studio IDE 里。在Visual Studio IDE 里创建窗体只需拖动并放置窗体到Office文档中。 开发者能够访问Visual Studio IDE 中的许多工具和功能,例如智能感知、拖放控件和数据 源。VSTO 也提供了Ribbon 可视化设计器,用于通过使用简单的.NET 应用程序编程模型自 定义Office功能区和编程。 ■ 1.1.2 VSTOVVCC 可以选择使用Visual Basic.NET 或者Visual C# 语言进行VSTO 开发。本书只讲述以C#为 第 第 第VVVVVVVV1.5 使用帮助系统 在使用Visual Studio 编程过程中遇到疑难问题时,既可以通过互联网搜索相关问题,也 可以在编程环境中按下快捷键【F1】,搜索微软提供的MSDN帮助。 ■1.5.1 设置帮助查看方式 在Visual Studio 中,有以下两种查看帮助的方式: ●在浏览器中启动。 ●在帮助查看器中启动。 可以通过单击菜单【帮助/设置帮助首选项】来选择查看方式。默认的查看方式为浏览 器查看方式,也就是说,当用户在编程过程中按下【F1】键时,会启动默认的网页浏览器 并跳转到相应的微软MSDN页面。 为了编程的方便,笔者建议选择在帮助查看器中启动。 ■1.5.2 下载和安装Help Viewer 如果用户选择“在帮助查看器中启动”,当在Visual Studio 中按下【F1】键,或者单 击菜单【帮助/查看帮助】时,则会自动启动Help Viewer 。 ■1.5.3 管理帮助内容 如果是初次使用Help Viewer ,这个查看器中没有任何的帮助内容。为此,需要事先下 载必要的帮助内容到计算机。 在Help Viewer 中切换到“管理内容”选项卡,选择添加如下帮助内容: ●Visual Studio 2012 :基础。 ●Visual Studio 2012:Visual Studio 中的Office开发。 ●Visual Studio 2012:Visual Basic 和Visual C# 。 然后单击右下角的“更新”按钮,稍后就会自动下载这些内容到计算机,如图1.20 所示。 本章要点回顾 ● VSTO 是一种全新的Office 开发技术,开发人员可以使用C#或VB.NET 语言访问 Office对象。 ● Visual Studio 是微软开发的功能强大的程序开发环境。本章讲述了在安装Visual Studio的中间步骤中,一定要勾选VSTO 开发。 ● 从创建最简单的C# 项目到控制台应用程序,加深对Visual Studio 开发环境以及C#解 决方案组织结构的理解。 第 第 第VVVV VVVV 续表 类型描V允许C值 char 字符型一个Unicode字符,存储0~65 535之间的整数 string 字符串 bool 布尔型true或false ■ 2.1.2 赋值运算符 赋值语句的语法格式为: 变量名称=表达式; 表达式可以是一个常量,也可以是一个变量或者是任意组合起来的可以计算的表达式。 除了使用=作为赋值运算符外,C#还允许的几种赋值运算符,如表2.2所示。 表2.2 C#赋值运算符 赋值运算符示例含义 += a+=b 等价于a=a+b -= a-=b 等价于a=a-b *= a*=b 等价于a=a*b /= a/=b 等价于a=a/b %= a%=b 等价于a=a%b ++ i++ i自加1,等价于i=i+1或i+=1 i-i 自减1,等价于i=i-1或i-=1 ■ 2.1.3 变量CC用范围 变量的作用范围和其声明的位置有关系,可以在类模块的顶部、过程内部、语句块内 部或者循环体内部声明变量。换言之,在声明范围之外,是不能访问和使用这个变量的。 以下代码是一个典型的使用变量的方法,代码中先后声明了一个整型变量和一个字符 串变量,最后把两个变量连接在了一起。 注意如果表达式中+的两端有字符串数据,则+的含义是连接字符串,而不是数学中 的相加。 1 public void 变量的声明和赋值() 2 { 3 int i; 4 i = 34; 5 string s = @"e:\ab\cd.txt"; 6 result = i + s; 7 } 相应的VBA语法为: 第 第 第CC CCCC VSTO开发入门教程 1 Public Sub 变量的声明和赋值() 2 Dim i As Integer3 i = 34 4 Dim s As String5 s = "e:\ab\cd.txt" 6 result = i & s 7 End Sub 2.2 字符C字符串处理 字符和字符串类型是编程中最常用的数据类型。编程过程中会涉及字符串的提取、拆 分等操作。 ■2.2.1 字符变量 字符变量的声明格式为: char 字符变量; 例如,char MyChar ='d' 就声明了一个字符变量并赋初值。表达一个字符常量,必须加 上单引号,而不是双引号。 字符变量经常用来代表ASCII码表中的字符。上述的'd'转换为整型数就是100,ASCII 码表可以用下面的公式产生。 创建一个名为“WindowsFormsApplication20160606 ”的窗体应用程序,在窗体上放置 一个listbox列表框控件,然后在窗体的Load事件中写入如下代码: 1 private void Form1_Load(object sender, EventArgs e) 2 { 3 this.listBox1.Items.Clear(); 4 for (int i = 0; i <= 127; i++) 5 { 6 char a = Convert.ToChar(i); 7 this.listBox1.Items.Add(i.ToString() +"\t" +a); 8 } 9 } 上述代码把0~127这128个字符的代码值和符号添加到列表框中,运行效果如图2.1 所示。 此外,字符变量可以和整型变量直接进行运算。比如下面两行代码,变量j等于650, 原因是abc是字符变量,存储了常量A,而A的ASCII码值是65,因此j是65和10的乘积。 1 char abc='A'; 2 int j = abc * 10; ■ 2.2.6 格式化字符串 String.Format函数的语法为: String Format(要输出的字符串,变量列表) 要输出的字符串中,允许使用{数字}这样的占位符,输出时占位符位置用变量列表 中相应位置的变量来替换,具体看下面的例子。 1 public void 格式化字符串() 2 { 3 string s0="format",s1="micro",s2="soft",s3 ="visual" ,s4="studio"; 4 result =String.Format("result is {0} {3} {4}",s0,s1,s2,s3,s4); 5 } 上面这个例子依次声明并赋值了5个字符串变量。注意第4行代码,依次把5个变量置 于Format函数的参数中,要返回的是双引号括起来的部分,遇到{n}就表示该位置用第n个 字符串变量代替,因此result返回的结果是:result is format visual studio。 ■ 2.2.7 字符串C替换 C#中使用Replace函数进行字符串的替换 。 Replace函数有以下两种用法 : ①字符替换。语法格式如下: Replace(旧字符,新字符) ②字符串替换。语法格式如下: Replace(旧字符串,新字符串) 1 string s = "Microsoft Office"; 2 string t = s.Replace('o', '%'); 3 string u = s.Replace("oso", "微软公司"); 上述代码中,变量t返回“Micr%s%ft Office ”,变量u返回“Micr 微软公司ft Office ”。 ■ 2.2.8 字符串C数组 在编程实际应用中,经常会将一个字符串按照某个特定的符号进行分割。C#可以使用 Split函数实现字符串分割。 1 public void 字符串与数组( ) 2 { //字符串转数组 ; 3 string source = "micro soft visual studio" ; 4 string[] arr = source.Split(' ') ; 第 第 第CCCCCC5 foreach (string v in arr) 6 { result += v + "\n"; } 7 //数组转字符串 8 result += string.Join("+",arr); 9 } 上述代码中字符串数组arr用来存储使用空格分割开的source元素。反过来,可以使用 Join函数把字符串数组的每一个元素用特定的符号连接起来,成为一个新的字符串。 具有同样功能的VBA代码如下: 1 Public Sub 字符串与数组() 2 '字符串转数组 3 Dim source As String, arr, v4 source = "micro soft visual studio" 5 arr = Split(source, " ") 6 For Each v In arr 7 result = result & v & vbNewLine 8 Next v 9 10 Dim s(1 To 3) As String11 s(1) = "excel" 12 s(2) = "word" 13 s(3) = "ppt" 14 result = result & Join(s, "+++") 15 End Sub 2.3 逻辑运算 ■2.3.1 布尔型变量 布尔型变量只能等于true或false这两个逻辑值。布尔型变量或常量经常用于if语句中。 1 public void 布尔型变量() 2 { 3 bool flag; 4 flag = (1 > -1); 5 result = flag.ToString(); 6 } 具有同样功能的VBA代码如下: 1 Public Sub 布尔型变量() 2 Dim flag As Boolean3 flag = (1 > -1) 4 result = flag5 End Sub ■ 2.3.2 C较运算符 C#中的比较运算符如表2.4所示。 表2.4 C较运算符 运算符含义示例 = = 等于5==3+2,返回true ! = 不等于5!=3+2,返回false < 小于5<3+2,返回false > 大于5>3+2,返回false < = 小于等于5<=3+2,返回true > = 大于等于5>=3+2,返回true 注意C#表示逻辑等于的符号是连续两个等于号。 ■ 2.3.3 多条件CC或非运算 很多情况下,需要多个逻辑表达式通过布尔运算符连接组合使用,才能表述一个实际 的逻辑判断,例如判断一个年份是否是闰年。与或非运算符如表2.5所示。 表2.5 C或非运算符 运算符含义说明 ! 非 !加在一个逻辑表达式之前,如果原表达式为true,则返回false;如果原表达式为 false,则返回true & & 与所有表达式均为true,才返回true | | 或至少有一个表达式为true,就返回true;如果所有表达式均为false,则返回false 如果要判断一个字符是否是大写英文字母,可以使用如下代码中的逻辑表达式表述: 1 char var1 = 'W'; 2 if (var1 >= 'A' && var1 <= 'Z') 3 { MessageBox.Show(var1 + "是一个大写字母"); } 4 else 5 { MessageBox.Show(var1 + "不是大写字母"); } 如果要判断一个字符是否是英文字母,需要使用或运算符: 1 char var1 = 'b'; 2 if (var1 >= 'A' && var1 <= 'Z' || var1 >= 'a' && var1 <= 'z') 3 { MessageBox.Show(var1 + "是一个英文字母"); } 4 else 5 { MessageBox.Show(var1 + "不是英文字母"); } 观察下面的实例代码,思考一下result返回值是什么。 1 public void 多条件的与或非运算() 2 { 第 第 第CCCCCC3 bool flag; 4 flag = !(true && false || true); 5 result = flag.ToString(); 6 } 具有同样功能的VBA代码如下: 1 Public Sub 多条件的与或非运算() 2 Dim flag As Boolean3 flag = Not (True And False Or True) 4 result = flag5 End Sub 2.4 不同类型C强制转换 编程过程中,有时候需要把一个类型的数值赋值给另一个类型的变量,如果源类型和 目标类型是同种类型的,则直接赋值即可,这称作隐式转换。如果源类型和目标类型是不 同类型的,则需要进行显式转换,否则会提示出错。 下面的4行代码可以正常运行,因为int类型的数据可以直接赋值给long类型;float类型 的数据也可以直接赋值给double类型。 1 int I = 32; 2 long L = I; 3 float FLT = 3.14F; 4 double D = FLT; ■2.4.1 ToString 要把一个数据显示在MessageBox对话框中,或者显示在窗体的文本框中,都需要事先 把变量或计算结果转换为string类型才行。以下代码,把整型变量I显示在窗体上的富文本 框中。 1 int I = 32; 2 this.richTextBox1.Text =I.ToString(); ■2.4.2 Parse 与ToString功能相反,Parse可以把字符串转换为其他数据类型。 1 string temp ="1"; 2 int i = int.Parse(temp); 3 float f = float.Parse(temp); 4 char c = char.Parse(temp); 5 6 string s = "false"; 7 bool b = bool.Parse(s); 8 9 string d = "2016-8-8"; 10 DateTime dt = DateTime.Parse(d); 上述代码分别把字符串类型的数据转换为整型、浮点型、字符型、布尔型以及日期时 间型。 ■ 2.4.3 Convert C#还可以使用System.Convert来转换数据类型。例如下面这句代码,把字符串转换为 double类型。 double p = System.Convert.ToDouble(“3.14”) ; System.Convert常用数据类型转换函数如表2.6所示。 表2.6 System.Convert常用数据类型转换函数 转换函数 ToString( 原类型 ) ToBoolean( 原类型 ) ToDouble( 原类型 ) ToInt32( 原类型 ) ToDateTime( 原类型 ) 说明 把原类型数据转换为字符串 把原类型数据转换为布尔型 把原类型数据转换为双精度 把原类型数据转换为32位整型 把原类型数据转换为日期时间类型 除了上述的转换方法外,还可以在原数据前面放一个括号,括号内是目标数据类型的 名称。如下代码: 1 int m = 3; 2 double d =(double)m; 上述代码把整型数据m赋值给双精度变量d。 以下代码演示了最常用的数据类型的转换,读者自行调试体会。 1 public void 不同类型的强制转换() 2 { 3 int i = 30; 4 string s = i.ToString();//整型转字符串 5 s = "30.65"; 6 float f = float.Parse(s); //字符串转浮点型 7 double d = (double)f; //浮点型转双精度型 8 int j = (int)d; //双精度型转整型 9 result = i + s + f + d + j + ""; 10 } 具有同样功能的VBA代码如下: 第 第 第 CC CCCC 1 Public Sub 不同类型的强制转换() 33 2 Dim i As Integer, s As String, f As Single, d As Double, j As Integer 3 i = 30 4 s = CStr(i) '整型转字符串 5 s = "30.65" 6 f = CSng(s) '字符串转浮点型 7 d = CDbl(f) '浮点型转双精度型 8 j = CInt(d) '双精度型转整型 9 result = i & s & f & d & j & "" 10 End Sub 2.5 使用数组 声明一个变量,只能容纳一个数据,如果有相同类型的多个数据,可以使用数组来提 高编程效率。 ■ 2.5.1 数组C声明和初始化 数组的声明与变量的声明非常相似,声明一个整型变量的语法格式为: int i; 那么声明一个整型数组的语法格式为: int[] arr; 可以看出声明数组时,只需要在数据类型后加一对中括号即可。 声明数组的时候,也可以像变量一样,直接赋值。 1 int[] n1 = new int[10]; 2 int[] n2 =new int[10]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 3 int[] n3 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 上述代码,声明了三个整型数组,其中数组n1只声明而没有赋给任何值;n2和n3在声 明的同时,完成数组的初始化。 如果要为数组n1赋值,可以通过下标,逐个赋值,例如n1[2]=3。 ■ 2.5.2 一维数组 下面以计算1~10之间的奇数和为例,说明一维数组的用法。 1 int[] a= { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 2 int total = a[0] + a[2] + a[4] + a[6] + a[8]; 上述代码中,第1行声明了一个具有10个元素的整型数组,第2行代码累加数组a的5个 VSTO 开发入门教程 34 元素。C#数组的下标是从0开始的,因此上述代码相当于累加1+3+5+7+9,最后变量total返 回25。 注意 C#数组的下标是从0开始的。 ■ 2.5.3 数组元素C遍历 还是以上面的数字加和问题为例,说明如何使用循环处理数组。 1 public void Sum() 2 { 3 int[] n = new int[10]; 4 for (int i = 0; i < n.Length; i++) 5 { 6 n[i] = i + 1; 7 } 8 int total = 0; 9 for (int i = 0; i < n.Length; i = i + 2) 10 { 11 total += n[i]; 12 } 13 MessageBox.Show(total.ToString()); 14 } 上述代码中,第4行到第7行,使用for循环为数组n赋初值。第8行把总和变量total初始 化为0,第9行到第12行这个for循环体,步长为2,访问数组n中的奇数,累加给total,最后 返回25。 代码中n.Length表示数组的长度,也就是指数组中元素个数。 为了加深对数组的理解和认识,再举一个用数组处理斐波那契数列的问题。 斐波那契数列是数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例 子引入的有趣数列,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、 8、13、21、34、…,可以看出该数列前两项固定为0和1,从第三项起,每一项均等于该 项前面两项之和。 在数学上,斐波纳契数列以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n- 1)+F(n-2)(n≥2,n∈N*)。 因此可以使用C#中的数组打印出斐波那契数列的前20项: 1 public void Fibonacci() 2 { 3 int[] F = new int[20]; 4 F[0] = 0; 5 F[1] = 1; 6 for (int i = 2; i < F.Length; i++) 7 { 第 第 第 CC CCCC 8 F[i] = F[i - 2] + F[i - 1]; 35 9 } 10 string result = ""; 11 for (int i = 0; i < F.Length; i++) 12 { 13 result += F[i].ToString()+ " "; 14 } 15 this.richTextBox1.Text =result; 16 } 上述代码中,第4行到第9行为数组F赋值,第11到第14行再次使用for循环遍历斐波那 契数组各个元素,并且把每一个元素追加到result之后,最后在富文本框中显示如下内容: 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 以下代码是典型的用于处理数组的示例,读者自行调试体会。 1 public void 一维数组() 2 { 3 string[] arr = { "ab", "cd" }; 4 int[] a = new int[3]; 5 a[0] = 3; a[1] = 4; a[2] = 5; 6 result = arr[0] + arr[1]; 7 foreach (var v in a)//遍历数组元素 8 { 9 result += v.ToString(); 10 } 11 } 具有同样功能的VBA代码如下: 1 Public Sub 一维数组() 2 Dim arr(0 To 1) As String 3 arr(0) = "ab": arr(1) = "cd" 4 Dim a(0 To 2) As Integer 5 Dim v 6 a(0) = 3: a(1) = 4: a(2) = 5 7 result = arr(0) + arr(1) 8 For Each v In a '遍历数组元素 9 result = result & v 10 Next v 11 End Sub ■ 2.5.4 二维数组 二维数组用来存储二维方阵数据,比如存储中国各省的省会城市,省的简称等信息。 1 public void province() 2 { 3 string[,] p = new string[5, 3] { { "河北省", "冀", "石家庄" }, { "河 南省", "豫", "郑州" }, { "湖北省", "鄂", "武汉" }, { "湖南省", "湘", "长沙" }, { "江苏 省", "苏", "南京" } }; 第 第 第 CC CCCC 遍历到全部元素,以下是典型的处理二维数组的代码,读者自行调试体会。37 1 public void 二维数组() 2 { 3 int[,] a = { { 1, 2, 3 }, { 4, 5, 6 } }; 4 result = a[0, 0] + "\t" + a[1, 2]; 5 string[,] arr = new string[2, 4]; 6 for (int i = 0; i < 2; i++)//二维数组赋值 7 { 8 for (int j = 0; j < 4; j++) 9 { 10 arr[i, j] = (i * 10 + j).ToString(); 11 } 12 } 13 result += arr[1, 1]; 14 } 具有同样功能的VBA代码如下: 1 Public Sub 二维数组() 2 Dim arr(0 To 1, 0 To 3) As String 3 Dim i As Integer, j As Integer 4 For i = 0 To 1 '二维数组赋值 5 For j = 0 To 3 6 arr(i, j) = (i * 10 + j) 7 Next j 8 Next i 9 result = arr(1, 1) 10 End Sub 2.6 条件选择C句 C#中分支控制结构有三种方式: ● 三元运算符 ● If…else if…else语句 ● switch语句 ■ 2.6.1 三元运算符 语法如下: result = condition? trueCase : falseCase 首先判断condition是否成立,如果成立,则把trueCase赋给result,反之把falseCase赋给 result。 VSTO 开发入门教程 38 1 int q=8; 2 string result = (q % 2 == 1) ? "奇数" : "偶数"; 3 MessageBox.Show(q+ "是" +result); 上述代码,第2行首先判断q对2求余,结果是否为1,如果是1,则为奇数,否则为偶 数。运行后,对话框显示“8是偶数”。 下面再举一个简单选择语句的实例: 1 public void 简单选择语句() 2 { //逻辑表达式?结果1:结果2 3 int i = 11; 4 int j = 2; 5 result = i % j == 0 ? "100" : "-100"; 6 } 运行代码后,result返回-100。 具有同样功能的VBA代码如下: 1 Public Sub 简单选择语句() 2 'IIF 3 Dim i As Integer, j As Integer 4 i = 11 5 j = 2 6 result = IIf(i Mod j = 0, 100, -100) 7 End Sub ■ 2.6.2 ifC句 if语句是最常用的分支控制语句,典型的代码范例如下: 1 public void if语句() 2 { 3 int i = -3; 4 if (i > 0) 5 { result = "正数"; } 6 else if (i < 0) 7 { result = "负数"; } 8 else 9 { result = "零"; } 10 } 上述代码判断整型变量i的正负情况,如果i大于0,则只执行if后面的语句块;如果i小 于0,则只执行elseif后面的语句块;所有条件都不成立,则执行else后面的语句块。 使用if的过程中,要注意if以及else if后面的条件必须用圆括号括起来,每一个分支的 语句块最好用花括号括起来。 具有同样功能的VBA代码如下: 第 第 第 CC CCCC 1 Public Sub if语句() 39 2 Dim i As Integer 3 i = -3 4 If (i > 0) Then 5 result = "正数" 6 ElseIf (i < 0) Then 7 result = "负数" 8 Else 9 result = "零" 10 End If 11 End Sub 为了说明if语句中花括号的功能,分析如下代码: 1 public void TestIf() 2 { 3 int i = 0; 4 if (true) 5 { 6 i++; 7 i++; 8 } 9 else 10 i--; 11 i--; 12 MessageBox.Show(i.ToString()); 13 } 运行该过程,对话框会显示1,而不是2。这是因为,if语句中的条件为true,表示if 分支恒成立,因此执行语句块中的两行自加代码,i变为2。比较一下代码中第10行和第11 行,由于第10行属于else后的语句,因此不被执行。但是第11行不属于if…else语句结构范 围,因此无论if结构哪一个分支成立,第11总是执行。为此,对话框返回1。 如果我们把第10行和第11行代码用花括号括起来,则构成了一个语句块,属于else分 支,这时候对话框会返回2。 如果我们把第10~12行用花括号括起来,则这三行都属于else分支,这时候运行代码 后不出现任何对话框。 ■ 2.6.3 switchC句 switch语句非常类似于if语句,因为它是根据测试的值来有条件地执行代码。 下面的代码用来判断变量i的奇偶性,因此要把比较的数值放在switch后的括号内。i和 下面每一个case后的数值作比较,如果相等,则执行其后的语句块。下面代码的含义是: 如果i等于1或3或者5,则返回奇数;如果等于2、4、6中的任何一个,则返回偶数;如果所 有的case都没匹配上,则执行default后的语句块。 VSTO 开发入门教程 40 1 public void switch语句() 2 { 3 int i = 3; 4 switch (i) 5 { 6 case 1: 7 case 3: 8 case 5: 9 result = "奇数"; 10 break; 11 case 2: 12 case 4: 13 case 6: 14 result = "偶数"; 15 break; 16 default: 17 result = "不明确"; 18 break; 19 } 20 } 具有同样功能的VBA代码如下: 1 Public Sub Select语句() 2 Dim i As Integer 3 i = 3 4 Select Case (i) 5 Case 1, 3, 5 6 result = "奇数" 7 Case 2, 4, 6 8 result = "偶数" 9 Case Else 10 result = "不明确" 11 End Select 12 End Sub 2.7 循环C句 循环,就是指反复执行同一个动作。在C#中,用于循环的结构有: ● while循环 ● do循环 ● for循环 ● foreach循环 ■ 2.7.1 while循环 while的语法结构与if语句非常类似,不同的是,if后面的语句块只执行一次,而while 第 第 第 CC CCCC 后的语句块反复执行,直至while括号内条件不成立。41 1 public void while循环() 2 { 3 int i = 10; 4 while (i > 0) 5 { 6 result += i + "\n"; 7 i--; 8 } 9 } 上述代码中,i的初值为10,判断i是否大于0,如果条件成立不断地往result中追加i, 并且i自减1。因此result最后返回的结果是:10 9 8…3 2 1,因为i为1时,仍然输出,但是自 减之后,i变为0,while后的条件不再成立,跳出循环。 具有同样功能的VBA代码如下: 1 Public Sub while循环() 2 Dim i As Integer 3 i = 10 4 While (i > 0) 5 result = result & i & vbNewLine 6 i = i - 1 7 Wend 8 End Sub ■ 2.7.2 do循环 与while循环相比,do循环首先执行一次其后的语句块,然后判断条件是否成立,如果 成立则继续执行语句块,如果不成立,则退出do…while循环。 1 public void do循环() 2 { //至少执行一次循环体内容 3 int i = 10; 4 do 5 { 6 result += i + "\n"; 7 i--; 8 } 9 while (i > 0); 10 } 上述代码i初值为10,首先往result后面追加10,然后自减1,然后判断i是否大于0;如 果大于0,则继续执行do后的语句块;如果不大于0,则退出循环。 因此,上述代码result最终显示10,9,8,…,3,2,1这10个数字。 具有同样功能的VBA代码如下: VSTO 开发入门教程 42 1 Public Sub do循环() 2 '至少执行一次循环体内容 3 Dim i As Integer 4 i = 10 5 Do 6 result = result & i & vbNewLine 7 i = i - 1 8 Loop While (i > 0) 9 End Sub ■ 2.7.3 for循环 如果要使用固定次数的循环,则该考虑使用for循环。for循环圆括号内分三个部分,依 次是初值设定、条件判断和处理。 1 public void for循环() 2 { 3 for (int i = 1; i < 5; i++) 4 { 5 result += i + "\n"; 6 } 7 } 上述代码中,for循环体内声明一个整型变量i,判断如果i小于5,则执行for循环体的语 句块部分,接着自加1,继续判断是否小于5,如此反复执行,直至i不小于5。因此上述代 码result最终结果为:1 2 3 4。 注意 for循环体内三个部分是用半角分号隔开,而不是逗号。 具有同样功能的VBA代码如下: 1 Public Sub for循环() 2 For i = 1 To 4 Step 1 3 result = result & i & vbNewLine 4 Next i 5 End Sub 下面再举一个典型的循环实例加深印象:累加从1到100之间所有的偶数之和。 1 public void TestFor() 2 { 3 int total = 0; 4 for (int i = 2; i <= 100; i += 2) 5 { 6 total += i; 7 } 8 MessageBox.Show("偶数和为:" + total); 9 } 上述代码中,total的初值为0,循环变量i从2到100,步长为2,每循环一次,就把i累加 第 第 第 CC CCCC 给total,对话框显示“偶数和为2550”。43 ■ 2.7.4 foreach循环 foreach循环用于枚举集合类对象中的各个元素,例如列举字符串中的每个字符、数组 中的每一个元素等。 1 public void foreach循环() 2 { 3 int[] arr = { 1, 3, 5, 7 }; 4 foreach (int i in arr) 5 { 6 result += i + "\n"; 7 } 8 } 上述代码中,arr是一个整型数组,foreach循环体内使用变量i代表数组中的每一个元素。 具有同样功能的VBA代码如下: 1 Public Sub foreach循环() 2 Dim arr As Variant, v 3 arr = Array(1, 3, 5, 7) 4 For Each v In arr 5 result = result & v & vbNewLine 6 Next v 7 End Sub 2.8 流程控制C句 编程应用中,有时需要提前跳出循环,或提前进入下一轮循环。C#提供了4个命令用 来控制循环结构: ● break语句:立即终止循环,跳到循环体外。 ● continue语句:立即终止当次循环,继续执行下次循环。 ● goto语句:跳出循环,跳转到指定标记好的语句行上。 ● return语句:跳出循环,跳出包含该循环的过程或函数。 ■ 2.8.1 breakC句 1 public void break语句() 2 { //跳出循环 3 for (int i = 1; i < 5; i++) 4 { 5 if (i > 3) VSTO 开发入门教程 44 6 { break; } 7 else 8 { result += i + "\n"; } 9 } 10 } 上述代码,for循环体内嵌套有if语句,当i自加大于3的时候,跳出for循环,直接跳转 到代码中第10行。因此变量result最后的结果是1 2 3。 具有同样功能的VBA代码如下: 1 Public Sub exitfor语句() 2 '跳出循环,类似于C#中的break语句 3 Dim i As Integer 4 For i = 1 To 4 5 If (i > 3) Then 6 Exit For 7 Else 8 result = result & i & vbNewLine 9 End If 10 Next i 11 End Sub ■ 2.8.2 continueC句 continue语句的作用是越过循环体内continue之后的代码,直接进入下一次循环。 1 public void continue语句() 2 { //越过本次循环 3 for (int i = 1; i < 10; i++) 4 { 5 if (i == 3 || i == 7) 6 { continue; } 7 else 8 { result += i + "\n"; } 9 } 10 } 上述代码,当i循环到3或者7时,什么都不做,直接让i自加继续循环。因此代码中的 result最后的结果是:1 2 4 5 6 8 9。 ■ 2.8.3 gotoC句 goto语句的作用是跳转到指定的标号。 1 public void TestGoto() 2 { 3 int i; 4 int total = 0; 第 第 第 CC CCCC 5 for (i = 1; i <= 10; i++) 45 6 { 7 if (i > 5) 8 { 9 goto label1; 10 } 11 else 12 total += i; 13 } 14 label1: 15 MessageBox.Show(total.ToString()); 16 } 上述代码,循环变量i从1开始循环,当i不大于5时,把i累加给total,一旦i大于5,跳出 for循环,跳转到标号为label1的第14行,显示一个对话框。因此对话框显示的结果为1~5 的加和:15。 具有同样功能的VBA代码如下: 1 Sub testGoto() 2 Dim i As Integer 3 Dim total As Integer 4 For i = 1 To 10 5 If i > 5 Then 6 GoTo label1 7 Else 8 total = total + i 9 End If 10 Next i 11 label1: 12 MsgBox total 13 End Sub ■ 2.8.4 returnC句 return语句不只用于循环体内,也可以用在一般代码中。下面的代码,当i等于3时,代 码将直接跳转到第11行。因此result的最终结果是:1 2。 1 public void return语句() 2 { //return是跳出过程,break是跳出循环 3 for (int i = 1; i < 10; i++) 4 { 5 if (i == 3 || i == 7) 6 { return; } 7 else 8 { result += i + "\n"; } 9 } 10 result += "循环体外的语句;\n"; 11 } VSTO 开发入门教程 46 具有同样功能的VBA代码如下: 1 Public Sub exitsub语句() 2 '类似于C#中的return语句 3 Dim i As Integer 4 For i = 1 To 10 5 If (i = 3 Or i = 7) Then 6 Exit Sub 7 Else 8 result = result & i & vbNewLine 9 End If 10 Next i 11 result = result & "循环体外的语句" 12 End Sub 2.9 输出C话框(MessageBox) 我们经常使用消息对话框给用户一定的信息提示,如在操作过程中遇到错误或程序 异常,也会使用对话框。在C#中,MessageBox消息对话框位于System.Windows.Forms命 名空间中,一般的C#项目不会自动在每一个类模块上面加上这条指令。因此,要想让 MessageBox正常使用,一定要确认是否声明了这条指令。对于C#窗体应用程序或者新创建 的窗体类,一般会默认具有这条指令,不需用户再加。 一般情况下,一个消息对话框包含信息提示文字内容、消息对话框的标题文字、用户 响应的按钮及信息图标等内容。C#中允许开发人员根据自己的需要设置相应的内容,创建 符合自己要求的信息对话框。 ■ 2.9.1 MessageBoxCC MessageBox的完整语法格式如下: MessageBox.Show(String, String, MessageBoxButton, MessageBoxIcon, MessageBoxResult) 其功能是显示一个消息框,该消息框包含消息、标题栏标题、按钮和图标,并且接受 默认消息框结果、遵从指定选项并返回结果。 最简单的对话框语法是MessageBox.Show(String),也就是说,其他参数接受默认,只 规定显示内容即可。 注意 显示内容这一参数必须是String类型的结果值,如果是要显示其他类型数据, 请使用ToString()方法转换。 下面这个示例自定义了以下5个参数: VSTO 开发入门教程 48 ■ 2.9.3 自定义C话框C图标 对话框显示的图标用MessageBoxIcon枚举常量表示,如表2.7所示。 表2.7 MessageBoxIcon枚举常量 成员名称描V Asterisk 该符号是由一个圆圈及其中的小写字母 i 组成的 Error 该符号是由一个红色背景的圆圈及其中的白色 X 组成的 Exclamation 该符号是由一个黄色背景的三角形及其中的一个感叹号组成的 Hand 该符号是由一个红色背景的圆圈及其中的白色 X 组成的 Information 该符号是由一个圆圈及其中的小写字母 i 组成的 None 消息框未包含符号 Question 该符号是由一个圆圈和其中的一个问号组成的 Stop 该符号是由一个红色背景的圆圈及其中的白色 X 组成的 Warning 该符号是由一个黄色背景的三角形及其中的一个感叹号组成的 注意 不必死记硬背这些常量,编写代码时有自动成员提示。 ■ 2.9.4 自定义C话框默认按钮 MessageBoxDefaultButton参数规定了对话框显示后哪一个按钮是已选中按钮。 MessageBox默认按钮常量如表2.8所示。 表2.8 MessageBox默认按钮常量 名称含义 Button1 消息框上的第一个按钮是默认按钮 Button2 消息框上的第二个按钮是默认按钮 Button3 消息框上的第三个按钮是默认按钮 ■ 2.9.5 处理C话框C用户响应 前面讲到,对话框上可以规定多个按钮,如何判断单击了哪一个按钮呢?可以把 MessageBox.Show赋给一个DialogResult类型的变量。 1 DialogResult v; 2 v = MessageBox.Show("是否提交试卷?", "询问", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); 3 if (v == DialogResult.Yes) 4 this.Text = "提交"; 5 else if (v == DialogResult.No) 6 this.Text = "不提交"; 上述代码执行后,会出现一个带有“是”和“否”两个按钮的询问对话框,如图2.7 所示。 第 第 第 CC CCCC 上述代码定义的函数V,包含半径和高两个参数,由于返回的体积也是双精度类型, 51 所以函数定义部分V前面要加上double,而不是void。代码中第1行最前面的关键词public表 示这个函数是公有的,如果是private,则表示是私有的。 ■ 2.11.2 过程C函数C调用 在其他地方调用过程和函数时,写上过程和函数名称以及一对括号,括号内部写入传 递的参数即可。 例如,我们在窗体的Load事件中调用上节的圆柱体积函数: 1 private void Form1_Load(object sender, EventArgs e) 2 { 3 double vol; 4 double R = 2, H = 10; 5 vol= V(R,H); 6 MessageBox.Show(vol.ToString()); 7 } 上述代码中,计算半径为2、高为10的圆柱的体积。其中R和H是实际参数,第5行代码 调用了圆柱体积函数。当窗体启动时,对话框中显示125.6636。 调用函数时,可以在参数列表中写上形式参数,如果明确地写上形式参数名称,则各 个参数的出现顺序可以不分先后。例如,“vol= V(r:R,h:H);”表示计算半径为R、高为H的 圆柱的体积;而“vol= V(h:4, r:7);”则是计算半径为7、高为4的圆柱的体积。注意到这里 故意把半径部分写在了后面,但是同样不影响计算结果。 如果定义的函数没有返回值,则在定义函数时要使用void类型,而且在函数体内部, 不需要使用return来返回值。 下面的代码说明了无返回值函数的定义和调用: 1 public void 过程的定义和调用() 2 { 3 proc();//无参数过程 4 proc2(s: "hello", i: 123);//带参数过程 5 } 6 void proc() 7 { 8 result = "proc"; 9 } 10 void proc2(int i, string s) 11 { 12 result = i + s; 13 } 具有同样功能的VBA代码如下: VSTO 开发入门教程 52 1 Public Sub 过程的定义和调用() 2 proc '无参数过程 3 Call proc2(s:="hello", i:=123) '带参数过程 4 End Sub 5 Sub proc() 6 result = "proc" 7 End Sub 8 Sub proc2(i As Integer, s As String) 9 result = i & s 10 End Sub 下面的代码说明了函数的定义和调用: 1 public void 函数的定义和调用() 2 { 3 result = c(b: 4, a: 1).ToString();//可以颠倒参数顺序 4 } 5 int c(int a, int b) 6 { //返回2个参数的平方之差 7 return a * a - b * b; 8 } 具有同样功能的VBA代码如下: 1 Public Sub 函数的定义和调用() 2 result = c(b:=4, a:=1) '可以颠倒参数顺序 3 End Sub 4 Function c(a As Integer, b As Integer) As Integer 5 '返回2个参数的平方之差 6 c = a * a - b * b 7 End Function 2.12 类C创建和使用 C#中,类可以拥有自己的成员和函数,每个类以文件的形式存储于项目文件夹中。从 功能上分,类还分为非静态类和静态类。 本节视频:类的创建和使用.wmv ■ 2.12.1 非静态类 非静态类在被调用时,需要使用new关键字实例化方可访问和使用类的成员。下面通 过一个例子来说明非静态类的用法。 启动Visual Studio 2012,创建一个名为“WindowsFormsApplication20160625”的窗体 应用程序,在窗体Form1上放入一个button按钮控件。 单击菜单【项目/添加类】,在出现的对话框中重命名类名为UCase.cs,如图2.10所示。 VSTO 开发入门教程 54 21 return cnt; 22 } 23 } 24 } 上述代码中,第11~22行为笔者添加,其余部分为模板自动生成。countCapital函数的 实现原理是,用foreach循环遍历source字符串中的每一个字符,如果字符是大写字母,则 给cnt自加1,最后函数返回cnt。 下面演示如何在窗体中调用该类中的函数。 回到窗体的设计视图,双击button1,修改其单击事件过程: 1 private void button1_Click(object sender, EventArgs e) 2 { 3 UCase U = new UCase(); 4 MessageBox.Show(U.countCapital("Microsoft Office PPT").ToString()); 5 } 需要特别注意的是,第3行代码声明了一个Ucase变量U,那么U就是UCase类的一个实 例,接下来在第4行中,使用U.countCapital就调用了这个类中的函数。 启动调试,单击窗体上的按钮,对话框中出现5,这是因为字符串中含有5个大写字母。 ■ 2.12.2 静态类 静态类与非静态类的区别是,在被调用时,不需要使用new关键字来实例化,使用引 用类名称即可。在实际编程应用中,可以利用这一特点,把一些共用的变量或函数放在静 态类中。 往项目中添加静态类的方法和一般的类添加步骤是一样的。下面举一个例子,通过单 击窗体上的按钮,在按钮上显示已经单击了几次。 在上一小节的窗体应用程序中继续添加一个名为Counter的类,编辑该类中的代码为: 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace WindowsFormsApplication20160625 8 { 9 public static class Counter 10 { 11 public static int times = 0; 12 } 13 } 注意代码中第9行class Counter前面加了public static,这说明该类是静态类。该类中定 义了一个静态的公有整型变量times。 第 第 第 CC CCCC 在窗体的设计视图中继续添加一个名为button2的按钮控件,双击该按钮,编辑其Click 55 事件: 1 private void button2_Click(object sender, EventArgs e) 2 { 3 Counter.times++; 4 this.button2.Text = "已经单击:" + Counter.times + "次。"; 5 } 启动调试,每单击一次button2按钮,该按钮的标题文字就显示总共单击它的次数。 要使用静态类中的成员,只需要使用Counter.times即可,无需实例化。 2.13 using指令 C#中的using指令写在类模块的顶部,using的作用是把外部库导入进来,从而可以访 问这些外部库的成员。 比如System.Windows.Forms这个外部库,里面包含了MessageBox这个成员,也就是 说,想显示一个对话框,就需要这样写代码: System.Windows.Forms.MessageBox.Show("hello"); 我们可以看出,为了显示hello这么短一个单词,代码中需要写这么长一句,因此, 可以在模块顶部写上“using System.Windows.Forms;”,那么在以后写代码时,只需要写 MessageBox.Show就可以显示对话框了。 此外,还可以使用简称或别名来简化。例如,在类模块顶部写上: using FM = System.Windows.Forms; 那么在代码中,使用FM.MessageBox.Show也可以显示对话框。因为使用别名FM来代 替System.Windows.Forms。 2.14 错误处理 异常是在运行期间代码中产生的错误,或者由于代码调用的函数产生的错误。 例如我们用C#制作了一个乘法计算器,用户在窗体上的两个文本框分别输入被乘数和 乘数,单击一个按钮,在对话框中给出两个数的乘积。但是有些时候,用户在文本框中输 入的不是数字,而是其他字符,那么造成乘法无法算出,如果不加错误处理,将会导致程 序意外终止。 C#语言包含结构化异常处理的语法,用于异常处理的三个关键字是: ● try:包含抛出异常的代码。 VSTO 开发入门教程 56 ● catch:包含抛出异常时执行的代码。 ● finally:包含始终会执行的代码。 下面的示例,在try块中试图提取数组i中下标为3的元素,实际上该数组的最大下标为 2,故此一定会出错。出错后,首先执行catch块内的代码,然后执行finally中的代码。 1 public void 错误处理() 2 { 3 try 4 { 5 int[] i = { 1, 3, 5 }; 6 result = i[3].ToString(); //数组下标越界 7 } 8 catch (SystemException ex) 9 { 10 result = ex.Message; 11 } 12 finally 13 { 14 result += "\nfinally"; 15 } 16 } 以下是VBA中的错误处理方式: 1 Public Sub 错误处理() 2 On Error GoTo Err1: 3 Dim i(1 To 3) As String 4 result = i(4) '数组下标越界 5 Exit Sub 6 Err1: 7 result = Err.Description 8 End Sub 本章要点回顾 ● C#中的变量在使用前一定要声明,并且变量名称严格区分大小写。 ● 字符串处理过程中,掌握换行符、制表位等常用转义字符的使用技巧。理解C#字 符与字符串的联系和区别。 ● 掌握逻辑运算中的与或非连接运算符,这部分知识是选择结构的基础。 ● 理解数组的声明和初始化方法,数组元素的访问和遍历。 ● 选择结构与循环结构以及流程的跳转是语法中的重点知识。 ● 函数的定义以及函数的调用,要注意参数的正确传递。 ● 类的使用技术,可以在类中定义变量、函数和属性成员。注意一般类和静态类的区别。 VSTO 开发入门教程 58 类描V FileSystemInfo 为 FileInfo 和 DirectoryInfo 对象提供基类 Path 对包含文件或目录路径信息的 String 实例执行操作 StreamReader 实现一个 TextReader,使其以一种特定的编码从字节流中读取字符 StreamWriter 实现一个 TextWriter,使其以一种特定的编码向流中写入字符 StringReader 实现从字符串进行读取的 TextReader StringWriter 实现一个用于将信息写入字符串的 TextWriter TextReader 表示可读取有序字符系列的读取器 TextWriter 表示可以编写一个有序字符系列的编写器,此类为抽象类 上表中的每一个类都有一系列的用法,比如File类,这是一个处理文件的类,文件的 移动、删除、重命名、创建都可以用File类实现。而Path类和Directory类用来处理路径,也 就是文件夹。 ■ 3.1.2 V件CV件夹处理实例 下面的范例首先判断了abc.ppt文件是否存在,如果存在则删除。代码中第9行判断一个 文件夹是否存在。代码中第13行用GetFiles方法列出了文件夹中所有文件的完整路径。 1 public void 文件与文件夹操作() 2 { //using System.IO 3 bool b = System.IO.File.Exists(@"F:\abc.ppt"); 4 if (b==true) 5 { 6 result = b.ToString(); 7 System.IO.File.Delete(@"F:\abc.ppt"); //删除文件 8 } 9 bool f = Directory.Exists(@"F:\VSTO"); 10 if (f == true) 11 { 12 result =f.ToString(); 13 string[] arr = Directory.GetFiles(@"F:\VSTO"); //列举文件夹中所有文件 路径 14 for(int i = 0; i < arr.Length; i++) 15 { 16 result += arr[i] + "\n"; 17 } 18 } 19 } 与此对应的VBA代码如下: 1 Public Sub 文件与文件夹操作() 2 '引用Scripting runtime 3 Dim FSO As New Scripting.FileSystemObject 续表