• WORD


    Word Object Model 介绍

    首先,要开发出良好的程序,我们需要了解我们的开发平台,而Word本身是一个很复查的平台,我在这里先从Word的对象模型开始介绍。Word Object Model中一共包含有数百个不同类型的对象,其中最关键的也是最常用的是Application、Document、Range、Selection和Bookmark,他们的关系如下图:

    Word Object Model Abstract

    我来依次介绍这几个对象:

    Application 对象

    Application代表Word程序,而一个Word程序内可以包含多个Word文档。用通俗的话来说,无论你开几个Word文档,都是在一个Word进程里面管理。这我们以后会讲到的Excel不一样。同时Application又是所有Word对象根,你可以通过Application对象,获得其他对象。在Addin开发过程中,我们可以通过以下方式来获得Application对象:

        Globals.ThisAddIn.Application
    Document 对象

    Document对象代表着一个Word文档,即便你刚打开你的Word,是一个空的新文档,也会有一个Document。在开发过程中,以下这个属性从Application中获得当前的Document对象:

        Globals.ThisAddIn.Application.ActiveDocument

    此外Application对象也维护着一个集合,即Application.Documents,里面包含着现在所有打开的Word文档。

     

    Range 对象

    Range是一个比较特殊的对象(我其实都不知道如何用中文翻译贴切地翻译这个单词),在你日常使用Word的过程中,你甚至可能不会知道有这样一个对象存在,但如果你想通过程序方式修改Word正文的内容,Range是一个很关键的对象。用微软官方的表述,Range代表着文档中一片连续的区域,微软为它列出了一下几个特性:

    1. Range的组成成分可以是单独的插入点,也可以是一个文本范围或整个文档。
    2. Range包含非打印字符,例如空格、制表符和段落标记。
    3. Range可以是当前所选内容所表示的区域,也可以表示当前所选内容之外的区域。
    4. Range与始终可见的所选内容不同,它在文档中是不可见的。
    5. Range不随文档保存,仅存在于代码运行期间。

    我再为它加2条

    1. Range有明确的开始和结束,但不同的Range之间是可以有交集的
    2. Range的长度是在变化的,如果你往一个Range里面插入的一个单词,它的长度会自动变长。

    获得Range对象的方式很多,我们可以通过Document对象的Range(ref object Start = Type.Missing, ref object End = Type.Missing)方法,创建一个自定义的Range。通过Word中文档相关的对象都有一个Range属性,比如Paragraph.Range、Selection.Range。

     

    Selection 对象

    Selection代表着当前光标所选中的对象,我们在开发过程中这个对象会和Application.WindowSelectionChange一起使用。

       1:          //
       2:          // Summary:
       3:          //     Occurs when the selection changes in the active document window.
       4:          event ApplicationEvents4_WindowSelectionChangeEventHandler WindowSelectionChange;

    Delegate接口

       1:      [TypeLibType(16)]
       2:      [ComVisible(false)]
       3:      public delegate void ApplicationEvents4_WindowSelectionChangeEventHandler(Selection Sel);

     

     

    Bookmark 与 Content Control

    Bookmark即书签,在Word文档中做一个标记,方便查阅。开发过程中,我们可以基于Range来创建Bookmark。如:

       1:      // 将第一段文档标记为一个BookMark 
       2:      Word.Range range = Globals.ThisAddIn.Application.ActiveDocument.Paragraphs[0].Range;
       3:      range.Bookmarks.Add("JustinTest");

     

    至此我们已经介绍完毕了Word中的主要5个对象,现在我们运用我们学到的东西,来实开头视频中的那个插件

     

    插件:自定义Search面板

    我先定义一下我们要实现的功能点,获得Word文档的内容,取得与检索关键字相关的上下文并显示在ListView中,当用户点中ListView中的项目时,高亮显示Word文档中对应的内容。以下是如何实现这几个功能的介绍。

     

    获得Word的全文 
    要取得当前Word的全文,我们主要要解决两个问题。

    1. 如何获得当前的Document对象?
    2. 如何通过Document对象获得文档内容?

    对于第一个问题,因为搜索功能主要是写在Task Pane中的UserControl中(这一点在上一篇文章中已经有过介绍),所以取得Document对象的主要方法,是通过Application对象获得ActiveDocument的对象,即当前编辑的文档:

        Globals.ThisAddIn.Application.ActiveDocument

    对于第二个问题,我们有两个方法:首先,Document对象有Paragraphs集合,这个集合里面包含了每个段落的对象,而每个段落对象,都有Range属性,我们可以通过Paragraph.Range.Text,来获得每个段落的正文。其次Document对象有一个Range方法,通过它我们可以把整个Document作为一个Range。

     

    Search按钮代码

       1:          private void btnSearch_Click(object sender, EventArgs e)
       2:          {
       3:              // 清楚文档中的高亮显示
       4:              ClearMark();
       5:   
       6:              lvSearchResult.Items.Clear();
       7:              if (string.IsNullOrWhiteSpace(tbSearchText.Text))
       8:              {
       9:                  return;
      10:              }
      11:   
      12:              // 按段落检索
      13:              Word.Document currentDocument = Globals.ThisAddIn.Application.ActiveDocument;
      14:              if (currentDocument.Paragraphs != null &&
      15:                  currentDocument.Paragraphs.Count != 0)
      16:              {
      17:                  foreach (Word.Paragraph paragraph in currentDocument.Paragraphs)
      18:                  {
      19:                      MatchCollection mc = Regex.Matches(paragraph.Range.Text, tbSearchText.Text.Trim(), RegexOptions.IgnoreCase);
      20:                      if (mc.Count > 0)
      21:                      {
      22:                          foreach (Match m in mc)
      23:                          {
      24:                              try
      25:                              {
      26:                                  int startIndex = paragraph.Range.Start + m.Index;
      27:                                  int endIndex = paragraph.Range.Start + m.Index + m.Length;
      28:   
      29:                                  Word.Range keywordRange = currentDocument.Range(startIndex, endIndex);
      30:                                  
      31:                                  // 获取上下文信息
      32:                                  // 获取前两个单词的位置(如果有)
      33:                                  startIndex = GetStartPositionForView(paragraph, m, startIndex);
      34:   
      35:                                  // 获取后两个单词的位置(如果有)
      36:                                  endIndex = GetEndPositionForView(paragraph, m, endIndex);
      37:   
      38:                                  // 在ListView中展示检索的关键字以及其上下文
      39:                                  Word.Range range = currentDocument.Range(startIndex, endIndex);
      40:                                  ListViewItem item = new ListViewItem(range.Text);
      41:                                  item.Tag = keywordRange;
      42:                                  lvSearchResult.Items.Add(item);
      43:                              }
      44:                              catch (Exception ex)
      45:                              {
      46:                                  MessageBox.Show(ex.Message);
      47:                              }
      48:                          }
      49:                      }
      50:                  }
      51:              }
      52:          }

    介绍一下这段代码的几个功能点:

    1. 在Search功能开始时,先清除文档中的高亮显示(ClearMark方法稍后会介绍)。
    2. 分段落,依次查找关键字。
    3. 获得关键字的上下文,并放入ListView中显示。需要注意的时候,我在ListViewItem的tag对象里面,存入了Keyword在文档中的Range,为了ListView点击事件。

     

    ListView点击事件

       1:          private void lvSearchResult_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
       2:          {
       3:              ClearMark();
       4:              if (lvSearchResult.SelectedItems.Count > 0)
       5:              {
       6:                  Word.Range range = lvSearchResult.SelectedItems[0].Tag as Word.Range;
       7:   
       8:                  // 为了可以恢复被修改的Range,我先将该Range和原本的Color放入Class的成员
       9:                  _LastRange = range;
      10:                  _LastRangeBackColor = range.HighlightColorIndex;
      11:                  range.HighlightColorIndex = Word.WdColorIndex.wdYellow;
      12:              }
      13:          }

    总体来说这段代码很简单,我稍微介绍一下Range对象的使用,这里我修改了HighlightColorIndex属性,来修改文字的背景色,如果你修改字体相关的样式,可以通过Range.Font属性。(此外,我会在下一篇文中,介绍如何通过Range加超链接、书签或者Content Control)。

     

    其他方法

       1:          private void ClearMark()
       2:          {
       3:              if (_LastRange != null)
       4:              {
       5:                  _LastRange.HighlightColorIndex = _LastRangeBackColor;
       6:              }
       7:          }

    我在Search事件和ListView点击方法中都会先调用这个方法,它会使用在lvSearchResult_ItemSelectionChanged中保存的Range和Color,来恢复之前的样式。

     

    总结

    本文中,我介绍了Word对象模型的基本内容和我写的一个Word插件,包含对Application、Document和Range对象的操作。Word程序包含的内容是很多的,本来想把自己了解的Word知识一次写完,但写到这里发现已经写了很多了,怕大家会看得累眨眼,所以先发出来,再下一篇文章,我会进一步深入介绍Word插件开发。下次内容预告:

    1. 修改右键菜单
    2. 往文档中插入内容
    3. 添加超链接、书签
    4. 基于选中内容,显示悬浮框

     

    最后,本文范例的代码可以在这里下载

    转自:http://www.cnblogs.com/izualx/archive/2011/05/14/2046071.html

     

  • 相关阅读:
    Waiting for table flush 的原因及处理方法【转】
    oracle启动过程【转】
    Zookeeper运维总结【转】
    nginx禁用3DES和DES弱加密算法,保证SSL证书安全【转】
    firewalld的基础操作命令【转】
    yum安装nginx报错解决nginx: [emerg] unknown directive “stream“ in /etc/nginx/nginx.conf问题【转】
    Zookeeper升级新版本步骤【转】
    MySQL查询导出数据Excel【转】
    MySQL启动报错[ERROR] InnoDB: Trying to access page number 4294967295 in space 0, space name innodb_system, which is outside the tablespace bounds. Byte offset 0, len 16384, i/o type read【转】
    MySQL备库复制延迟的原因及解决办法【转】
  • 原文地址:https://www.cnblogs.com/qianyaoyuan/p/3018322.html
Copyright © 2020-2023  润新知