65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Late binding 进行 Word 自动化 - dynamic 关键字的使用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (14投票s)

2011 年 11 月 8 日

CPOL

2分钟阅读

viewsIcon

76768

downloadIcon

2046

本文简要介绍了使用后期绑定和 .NET Framework 4.0 中的动态关键字进行 Word 自动化。

引言

您是否需要开发一个 Word 自动化应用程序 (Microsoft Office Automation),该应用程序将支持所有 Word 版本? 确切的解决方案是什么?

答案是后期绑定。 在 C# 中,可以使用反射实现后期绑定,您可以在我的上一篇文章“Word 自动化”中查看它的实现。

本文介绍了使用 dynamic 关键字在 .NET Framework 4.0 中实现后期绑定的想法

动态关键字

这是在 VS 2010 中引入的新关键字,此类型将在编译时绕过静态检查。 也就是说,一个类型为 dynamic 的元素被假定支持任何操作,编译器不会给出任何错误。 但是在执行时,运行时将尝试使用反射来调用方法/属性,如果找到,则将执行该方法/属性,否则将提供运行时错误。 请参考 MSDN 链接 以获得关于 dynamic 关键字的更好理解。

延迟绑定

在早期绑定的情况下,我们必须直接引用(添加引用)到项目的 Office Word 对象库。结果是,只有该类型才能在项目内部使用,而在运行时,该 Word 版本应该安装在目标机器上。但是在后期绑定的情况下,只需使用程序 ID 创建 Word 应用程序实例,如下所示

Type wordType = Type.GetTypeFromProgID("Word.Application"); 
dynamic wordApplication = Activator.CreateInstance(wordType);  

这将提供一个安装了 Word 版本的 Word 应用程序对象。 之后,可以使用反射调用所有属性、函数等。无需在项目中静态添加任何 office 引用。 见下图

Referances.JPG

是否可以使用单个实现来支持所有 Microsoft Word 版本?

答案是肯定的,直到当前的 Word 版本 (2010)。 怎么做? 让我们举个例子。 我们有一个 Microsoft 提供的 API WordApplication.Documents.Open() ,用于将文档打开到文档集合。 您可以看到下面的语法,其中所有粗体字参数都是相同的。 当更改一个版本到下一个版本时,它们将添加新参数,方法是保持所有先前版本的 API 参数(顺序也一样)相同。

在我们的实现中,我们将仅提供用于打开文档的必需参数(使用粗体字表示)。 在所有其他 API 中,情况相同。 这就是支持多个版本的秘诀。

Office 2000

WordApplication.Documents.Open(FileName,ConfirmConversions,
    ReadOnly,AddToRecentFiles,PasswordDocument, PasswordTemplate,Revert, 
    WritePasswordDocument, WritePasswordTemplate,Format,Encoding, Visible);

Office 2003

WordApplication.Documents.Open(FileName,ConfirmConversions,
    ReadOnly,AddToRecentFiles, PasswordDocument, PasswordTemplate, Revert, 
    WritePasswordDocument,WritePasswordTempate,Format,Encoding, Visible, 
    OpenAndRepair, DocumentDirection,NoEncodingDialog, XMLTransform);

Office 2007

WordApplication.Documents.Open(FileName,ConfirmConversions,
    ReadOnly,AddToRecentFiles,PasswordDocument,PasswordTemplate,Revert,
    WritePasswordDocument,WritePasswordTemplate,Format,Encoding,Visible,
    OpenAndRepair, DocumentDirection, NoEncodingDialog, XMLTransform);  

Office 2010

WordApplication.Documents.Open(FileName,ConfirmConversions,ReadOnly,  
    AddToRecentFiles,  PasswordDocument,PasswordTemplate,Revert,
    WritePasswordDocument,WritePasswordTemplate,Format,Encoding,Visible,
    OpenAndRepair,DocumentDirection,NoEncodingDialog, XMLTransform) 

Using the Code

下面的代码示例给出了如何使用 dynamic 关键字从任何类型访问方法/属性的想法。

创建 Word 应用程序

dynamic _wordApplication = null;
dynamic _wordDoc = null;
public void CreateWordApplication()
{
       string message = "Failed to create word application. Check whether"
                + " word installation is correct.";
    Type wordType = Type.GetTypeFromProgID("Word.Application");
    if (wordType == null)
    {
             throw new Exception(message);
    }
      _wordApplication = Activator.CreateInstance(wordType);
      if (_wordApplication == null)
      {
            throw new Exception(message);
      }
}  

打开 Word 文档

public void CreateWordDoc(object fileName, bool isReadonly)
{    
    if (File.Exists(fileName.ToString()) && _wordApplication != null)
    {                
        object readOnly = isReadonly;
        object isVisible = true;
        object missing = System.Reflection.Missing.Value;
        // Open a given Word document.
        _wordDoc = _wordApplication.Documents.Open(fileName, missing,
                            isReadonly, missing, missing, missing,
                            missing, missing, missing, missing,
                            missing, isVisible);
    }            
} 

关闭 Word 文档

public bool CloseWordDoc(bool canSaveChange)
{
    bool isSuccess = false;
    if (_wordDoc != null)
    {        
        object saveChanges = null;                
        if (canSaveChange)
        {
            saveChanges = -1; // Save Changes
        }
        else
        {
            saveChanges = 0; // No changes
        }
        _wordDoc.Close(saveChanges);
        _wordDoc = null;
        isSuccess = true;
    }
    return isSuccess;
} 

关闭 Word 应用程序

public bool CloseWordApp()
{
    bool isSuccess = false;
    if (_wordApplication != null)
    {                                
        object saveChanges = -1; // Save changes
        _wordApplication.Quit(saveChanges);
        _wordApplication = null;
        isSuccess = true;
    }
    return isSuccess;
} 

获取字数统计

public int GetWordCount(string word)
{
    object wordDoc = _wordDoc;
    int count = 0;
    do
    {
        if (_wordDoc == null)
        {
            break;
        }
        if (word.Trim().Length == 0)
        {
            break;
        }
        _wordDoc.Activate();
        dynamic content = _wordDoc.Content;
        // Get the count from direct text inside the document.
        count += GetCountFromRange(_wordDoc.Content, word);    
        int rangeCount = _wordDoc.Comments.Count;
        for(int i = 1; i <= rangeCount;)
        {
            count += GetCountFromRange(_wordDoc.Comments.Item(i), word);
            break;
        }
        rangeCount = _wordDoc.Sections.Last.Headers.Count;
        for (int i = 1; i <= rangeCount; i++)
        { 
            count += GetCountFromRange(
            _wordDoc.Sections.Last.Headers.Item(i).Range, word);
        }
        rangeCount = _wordDoc.Sections.Last.Footers.Count;
        for (int i = 1; i <= rangeCount; i++)
        {
            count += GetCountFromRange(
            _wordDoc.Sections.Last.Footers.Item(i).Range, word);
        }
        rangeCount = _wordDoc.Shapes.Count;
        for (int i = 1; i <= rangeCount; i++)
        { 
            dynamic textFrame = _wordDoc.Shapes.Item(i).TextFrame;
            int hasText = textFrame.HasText;
            if (hasText < 0)
            {
                count += GetCountFromRange(textFrame.TextRange, word);
            }
        }            
    }
    while(false);
    return count;
} 

从范围获取字数统计

private int GetCountFromRange(dynamic range,string word)
{
    int count = 0;
    object missing = System.Reflection.Missing.Value;
    object matchAllWord = true;
    object item = 1; // Goto Page
    object whichItem = 1;// First page    
    _wordDoc.Goto(item, whichItem);            
    dynamic find = range.Find;
    find.ClearFormatting();
    find.Forward = true;
    find.Text = word;
    find.MatchWholeWord = true;
    find.Execute();
    bool found = find.Found;
    while (found)
    {
        ++count;
        find.Execute();
        found = find.Found;
    }
    return count;
}  
© . All rights reserved.