Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Все статьи »

Обсудить на форуме Обсудить на форуме

Объектная модель Word с точки зрения разработчика под .NET
В этом документе представлена информация о том, как с помощью Microsoft Visual Studio Tools for Office использовать преимущества объектов, доступных в Microsoft Office Word 2003. Особое внимание уделяется нескольким важным объектам и дается ряд примеров, иллюстрирующих операции с этими объектами. Вы научитесь работать с приложениями и документами Word 2003, а также узнаете, как применять важнейшие свойства и методы.

Аннотация

В этом документе представлена информация о том, как с помощью Microsoft Visual Studio Tools for Office использовать преимущества объектов, доступных в Microsoft Office Word 2003. Особое внимание уделяется нескольким важным объектам и дается ряд примеров, иллюстрирующих операции с этими объектами. Вы научитесь работать с приложениями и документами Word 2003, а также узнаете, как применять важнейшие свойства и методы.

Скачайте WordObject.exe по ссылке Microsoft Download Center.

Содержание

Введение
Приступаем к работе с проектом Word
Основы: документы и шаблоны
Краткий обзор объектной модели Word
Объект Application
Объект Document
Объект Selection
Объект Range
Объект Bookmark
Поиск и замена текста
Печать
Создание таблиц в Word
Резюме

Введение

Microsoft® Word, по-видимому, является сегодня одним из самых распространенных в мире программных продуктов. Большинство пользователей Word прекрасно обходятся без написания какого-либо кода, хотя Word предоставляет богатую и мощную модель объектов, обеспечивающую высокую степень его программируемости. Microsoft Visual Studio Tools for Office позволяет разработчикам обращаться к объектам, поддерживаемым объектной моделью Microsoft Office Word 2003, на любом .NET-совместимом языке, например Microsoft Visual Basic® .NET или Microsoft Visual C#®. Богатейшая функциональность Word полностью доступна из пользовательского кода. Приступая к работе с этой моделью, поначалу можно растеряться из-за обилия в ней объектов. К счастью, объекты Word упорядочены по иерархическому принципу, и вы можете начать освоение объектной модели с двух основных классов на вершине этой иерархии: Application и Document. Сосредоточиться именно на этих двух классах имеет смысл потому, что большую часть времени вы будете иметь дело либо с самим приложением Word, либо с его документами.

По мере изучения объектной модели Word, вы обнаружите, что она моделирует пользовательский интерфейс Word, благодаря чему легко догадаться, что объект Application является оболочкой всего приложения, каждый объект Document представляет один документ Word, объект Paragraph соответствует одному абзацу и т. д. У каждого из перечисленных объектов много методов и свойств, позволяющих манипулировать этими объектами и взаимодействовать с ними. Догадаться о предназначении большинства членов этих объектов, как правило, тоже нетрудно - как насчет метода PrintOut? Но отдельные методы и свойства не столь понятны, и иногда пользоваться ими правильно бывает совсем не просто. Как только вы освоите основы, вы поймете, что в функциональности пользовательского интерфейса Word нет ничего такого, чего нельзя было бы сделать программным способом. Программирование в позволяет автоматизировать часто повторяющиеся операции, а также расширять и настраивать функциональность, встроенную в Word.

В этом документе поясняется, как использовать преимущества многих объектов в Word 2003, и описываются некоторые свойства, методы и события каждого объекта. Вы научитесь работать с приложениями и документами Word, а также с их важнейшими методами и свойствами.

Примечание Программирование Word и его объектов из Visual Basic .NET сильно напоминает программирование в VBA. Visual Basic .NET, как и VBA, поддерживает необязательные параметры и позднее связывание (late binding). Однако при использовании объектной модели Word из C# возникает ряд проблем. Поскольку C# не поддерживает необязательные параметры, параметризованные свойства и позднее связывание, вам придется особым образом программировать обращение ко многим методам и свойствам объектов Word. Различия в программировании на Visual Basic .NET и C# показываются в этом документе по мере изложения материала.

Приступаем к работе с проектом Word

Создавая новый проект Office в Visual Studio .NET, вы можете выбрать создание нового проекта Word Document или Word Template, как показано на рис. 1.

Рис. 1. Вы можете создать в Visual Studio .NET проект Word Document или Word Template

Visual Studio .NET автоматически создает файл кода с именем ThisDocument.vb или ThisDocument.cs в новом проекте Word Document или Word Template. Откройте ThisDocument в своем проекте. Вы увидите, что за вас уже сгенерирован открытый (public) класс OfficeCodeBehind. Раскройте скрытую область Generated initialization code. Класс OfficeCodeBehind включает код, который служит оболочкой объектов Word.Document и Word.Application:

' Visual Basic
Friend WithEvents ThisDocument As Word.Document
Friend WithEvents ThisApplication As Word.Application
 
// C#
private Word.Application thisApplication = null;
private Word.Document thisDocument = null;

Следующие две переменные объявляются автоматически.

  • ThisDocument Представляет Word-объект Document и обеспечивает доступ ко всем членам Document, в том числе к методам, свойствам и событиям.
  • ThisApplication Представляет Word-объект Application обеспечивает доступ ко всем членам Application, в том числе к событиям.

Наличие этих двух предопределенных переменных позволяет легко обращаться к данным объектам Word из вашего кода без объявления отдельных объектов Word.Document или Word.Application - просто используйте ThisDocument и ThisApplication.

В следующих разделах исследуются объекты Document и Application и детально рассматривается ряд специфических членов этих объектов. Word предоставляет очень богатую объектную модель, и подробно описать все члены этой модели в одном документе просто невозможно. Здесь вы получите представление об объектной модели, достаточное для того, чтобы приступить к работе и в дальнейшем самостоятельно пользоваться встроенной справочной системой Word для более детального изучения объектной модели.

Совет В коде на Visual Basic .NET, представленном в этом документе, часто встречаются вызовы методов CType и DirectCast. Дело в том, что для проекта-примера включен параметр Option Strict, и Visual Basic .NET требует явного преобразования типов. Многие методы и свойства объектов Word возвращают типы Object. Например, процедуре _Startup передаются переменные с именами application и document и типом Object, а функция CType используется для их явного преобразования в объекты Word.Application и Word.Document соответственно. Тот, кто программирует на C#, наверняка оценит это решение. Однако, как вы потом увидите, не все средства Word идеально соответствуют концепции объектно-ориентированного программирования - иногда оказывается удобнее работать с отключенным параметром Option Strict. Об этих исключениях также будет рассказано в дальнейшем.

Основы: документы и шаблоны

Для эффективного программирования Word нужно сначала понять, как работает это приложение. У большинство операций, выполняемых программным способом, есть эквиваленты в пользовательском интерфейсе (UI), доступные как команды в меню и на панелях инструментов. Также существует нижележащая архитектура, обеспечивающая поддержку команд, выбираемых из UI. Одна из важнейших концепций - шаблоны (templates). Вероятно, вы уже знакомы с этой концепцией: шаблон Word может содержать стереотипный текст (boilerplate text), стили, код, панели инструментов, комбинации клавиш для быстрого доступа к командам и элементы автотекста (AutoText). Всякий раз, когда вы создаете новый документ Word, он базируется на каком-либо шаблоне; к именам файлов шаблонов добавляется расширение .dot, а к именам файлов документов - .doc. Новый документ связывается с шаблоном и получает полный доступ к его элементам. Если вы не указываете конкретный шаблон, новый документ создается на основе стандартного шаблона Normal.dot (он устанавливается при установке Word).

Информация о Normal.dot

Шаблон Normal.dot является глобальным, он доступен любому документу, который вы создаете. Вы могли бы при желании поместить весь свой код в Normal.dot и создавать все документы в своей среде на основе собственного шаблона Normal (Обычный). Но тогда его файл мог бы стать чрезмерно большим, поэтому более эффективное решение для многих разработчиков - создание собственных шаблонов для конкретных приложений. В документах, создаваемых на основе вашего шаблона, код из стандартного шаблона Normal по-прежнему доступен. При необходимости можно связывать документ с несколькими шаблонами в дополнение к шаблону Normal.

Шаблоны и ваш код

Контейнерами стилей и кода могут быть не только шаблоны; допускается написание кода и настройка стилей в индивидуальных документах без модификации шаблона, на котором основан документ. Выполняя ваш код, Word использует полностью определенную ссылку (fully qualified reference) на источник (в роли которого может выступать шаблон или документ), имя модуля и имя процедуры. Здесь прослеживается аналогия с пространствами имен, что позволяет разделять процедуры с одинаковыми именами. На рис. 2 показано диалоговое окно Customize для панелей инструментов, иллюстрирующее эту концепцию. Имя каждой процедуры дополняется именами модуля и проекта. В данном случае элемент, выбранный в правой секции, ссылается на процедуру TileVertical, которая содержится в модуле Tile в Normal.dot. Процедура SaveDocument, расположенная сразу под TileVertical, содержится в проекте отделенного кода (code behind project) активного документа.

Рис. 2. Ссылки на процедуры получают полностью определенные имена при их связывании с Toolbar

Совет Следует запомнить, что для документов и шаблонов в Word всегда действует правило "самый локальный" ("most local" rule). Если в Normal.dot, пользовательском шаблоне и текущем документе дублируется какой-то стиль, макрос или другой элемент, первым используется тот, который находится в данном документе, вторым - в пользовательском шаблоне и последним - в Normal.dot.

Стили и форматирование

Word позволяет форматировать документ двумя совершенно разными способами.

  • Прямое форматирование. Вы можете выделить текст и вручную применить к нему такие элементы форматирования, как шрифт, начертание (например полужирный или курсив), размер и т. д.
  • Применение стиля. Word поставляется со встроенными стилями, которые вы можете модифицировать для настройки своих документов. Применяя стиль к абзацу или выделенному фрагменту, вы применяете целый набор атрибутов. Стили хранятся в шаблонах и в документах.

Обычно стили применяются к целому абзацу, но можно использовать и стили символов (character styles), которые применяются к отдельному символу, слову или выделенному фрагменту внутри абзаца. Чтобы увидеть список стилей, выберите Format | Styles and Formatting; на экране появится окно Styles and Formatting, показанное на рис. 3, где выбран стиль абзаца Normal.

Рис. 3. Стиль абзаца по умолчанию - Normal

Модификация стилей

Щелкните поле с названием стиля, и оно превратится в раскрывающийся список, где из доступных вариантов выберите Modify. Вы можете модифицировать любой из встроенных стилей и при желании сохранить изменения в шаблоне, на котором основан ваш документ. Для этого установите флажок Add to template, как показано на рис. 4. Если этот флажок не установлен, изменения сохраняются в самом документе и не распространяются на шаблон документа.

Рис. 4. Изменение стиля

Работая с Word, используйте стили как можно интенсивнее. Стили упрощают управление форматированием сложных документов; при прямом форматировании вносить в оформление документа согласованные изменения очень трудно. Важно, чтобы вы понимали, как работают стили, - это позволит эффективнее использовать их в вашем коде.

Что такое знаки абзацев

Документ в пользовательском интерфейсе Word разбивается на слова, абзацы, разделы (sections) и т. д. Внутренне документ Word - не что иное, как большой поток символов. Одна часть этих символов (например буквы и цифры) предназначена для чтения, другая (вроде пробелов, табуляторов и символов возврата каретки) - нет. Каждый из служебных символов выполняет свою задачу.

Знак абзаца не просто отделяет абзацы друг от друга - он играет более важную роль в документе Word: с ним сопоставлена вся информация о форматировании абзаца. Если вы копируете абзац вместе со знаком абзаца, то копируете и его оформление (параметры форматирования). А если вы копируете лишь сам абзац (без знака абзаца), параметры его форматирования теряются после вставки в новое место.

Когда вы редактируете документ Word и нажимаете клавишу Enter, создается новый абзац - клон предыдущего (в смысле форматирования); при этом на новый абзац распространяется стиль или оформление предыдущего абзаца. После этого вы можете изменить оформление второго абзаца. С другой стороны, символ разрыва строки (line break), создаваемый нажатием клавиш Shift + Enter, просто вставляет в существующий абзац признак переноса строки - никакие параметры форматирования с ним не сопоставляются. Если вы примените какой-либо параметр форматирования к абзацу, он будет действовать на весь текст до и после символов разрыва строк.

Отличие символа разрыва строки от знака абзаца (в режиме отображения знаков абзацев) иллюстрирует рис. 5.

Рис. 5. Символ разрыва строки в отличие от знака абзаца не служит границей для текущего форматирования абзаца

Отображение символов конца абзацев

Случайно удалив знак абзаца, вы можете потерять оформление этого абзаца. Поэтому лучше всего настроить Word на отображение знаков абзацев, выбрав Tools | Options | View и установив флажок Paragraph marks в разделе Formatting marks, как показано на рис. 6.

Рис. 6. Установка флажка Paragraph marks в разделе Formatting marks диалогового окна Options

Краткий обзор объектной модели Word

На первый взгляд, объектная модель Word весьма запутанна, так как поначалу кажется, что многие объекты в ее иерархии перекрываются. Например, объекты Document и Selection являются членами объекта Application, но в то же время объект Document - член объекта Selection. Вдобавок и Document, и Selection содержат объекты Bookmarks и Range, как видно на рис. 7. В следующих разделах мы кратко рассмотрим объекты верхнего уровня и обсудим, как они взаимодействуют друг с другом.

Рис. 7. Объект Application содержит объекты Document, Selection, Bookmark и Range

Объект Application

Объект Application представляет приложение Word и является предком всех остальных объектов. Его члены обычно действуют на Word в целом. Вы можете использовать его свойства и методы для управления средой Word.

Объект Document

Объект Document занимает центральное место в программировании Word. Открывая существующий документ или создавая новый, вы создаете новый объект Document, добавляемый в Word-набор Documents. Документ, на который установлен фокус ввода, называется активным, и его представляет свойство ActiveDocument объекта Application.

Объект Selection

Объект Selection представляет текущий выделенный фрагмент. Выполняя какую-либо операцию в пользовательском интерфейсе Word (например задавая полужирное начертание), вы выделяете соответствующий текст и применяете к нему новый параметр форматирования. Объект Selection всегда присутствует в документе; если ничего не выделено, этот объект представляет курсор ввода (insertion point). Объект Selection также может представлять несколько непоследовательных блоков текста.

Объект Range

Объект Range представляет непрерывную (последовательную) область в документе и определяется позициями начального и конечного символов. Вы не ограничены одним объектом Range - в одном документе можно определить сразу несколько таких объектов. Вот характеристики объекта Range:

  • может включать только курсор ввода, диапазон текста или весь документ;
  • содержит непечатаемые символы вроде пробелов, табуляторов и знаков абзацев;
  • может быть областью, как соответствующей, так и не соответствующей текущему выделенному фрагменту;
  • является динамическим, т. е. существует до тех пор, пока выполняется создавший его код.

Если вы вставляете текст в конец диапазона, Word автоматически расширяет диапазон, чтобы охватить и новый текст.

Объект Bookmark

Объект Bookmark аналогичен объекту Range в том смысле, что представляет непрерывную область в документе и тоже имеет начальную и конечную позиции. Вы можете использовать закладки (bookmarks), чтобы помечать какое-либо место в документе, или как контейнер текста в документе. Объект Bookmark может охватывать что угодно - только курсор ввода или весь документ. В документе можно определить несоклько закладок. Следующие характеристики Bookmark отличают его от объекта Range:

  • вы можете присваивать имя объекту Bookmark;
  • он сохраняется вместе с документом и не уничтожается по завершении породившего его кода или после закрытия документа;
  • по умолчанию он скрыт, но вы можете сделать его видимым, установив свойство ShowBookmarks объекта View в True. (Объект View является членом объектов Window и Pane, которые содержатся в объектах Application и Document.)

Подведем промежуточный итог


Вот несколько вариантов использования объектов Selection, Range и Bookmark.
  • Закладки удобны в шаблонах. Например, шаблон делового письма может содержать закладки там, где нужно вставлять данные из базы данных. В период выполнения ваш код может создать новый документ на основе этого шаблона, получить данные из базы, найти именованную закладку и вставить текст в нужную позицию.
  • Если вы хотите изменить текст внутри Bookmark, используйте его свойство Range для создания объекта Range, а затем вызывайте один из методов этого объекта для изменения текста.
  • С помощью объекта Bookmark можно определить в документе стереотипный текст. Вы указываете его содержимое, используя в качестве источника объект Range или Selection. Впоследствии вы сможете переходить к различным объектам Bookmark по каким-либо условиям для копирования и вставки стереотипного текста в другие документы.

Это лишь малая часть вариантов применения этих объектов для построения мощных пользовательских приложений.

Объект Application

Word-объект Application представляет само приложение Word. Всякий раз, когда вы пишете код, вы начинаете с объекта Application. Через него можно обращаться к любым другим объектам и наборам (collections), предоставляемым Word, а также к методам и свойствам самого объекта Application.

Использование ThisApplication

Если вы работаете в Word, объект Application создается автоматически, и вы можете через свойство Application получить ссылку на Word-объект Application. Создавая решения в Visual Studio .NET, вы можете использовать переменную ThisApplication, которая определяется за вас внутри класса OfficeCodeBehind.

Если вы программируете Word вне этого класса, то должны сами создать объектную переменную для Word-объекта Application, а затем создать экземпляр Word:

' Visual Basic
Dim appWord As Word.Application = _
 New Word.Application
 
// C#
Word.Application appWord = new Word.Application();

Совет Переменная Word.Application, объявленная в вашем классе OfficeCodeBehind, позволяет работать так же, как и при использовании ThisApplication. Однако при этом нужен дополнительный шаг для явного создания новой переменной Word.Application, тогда как ThisApplication создается автоматически.

При ссылках на объекты и наборы, расположенные в иерархии ниже объекта Application, явно ссылаться на объект Application не требуется. Например, вы можете ссылаться на активный документ через встроенное свойство ThisDocument, не указывая объект Application. ThisDocument ссылается на активный документ и позволяет работать с членами объекта Document. (Об этом объекте будет детально рассказано позже.)

Совет Вероятно, чаще всего вы будете пользоваться свойством ThisApplication.ActiveDocument, которое ссылается на активный объект Document. Но, как правило, удобнее работать с синтаксисом ThisDocument, а не ThisApplication.ActiveDocument. Дело в том, что в первом случае вам придется полностью определять ссылку с указанием объекта Application. Применение ThisDocument эффективнее, так как нужная переменная уже создана за вас.

Свойства Application

Получив ссылку на объект Application, вы можете работать с его методами и свойствами. Этот объект предоставляет большой набор методов и свойств, позволяющих программно управлять Word. Большинство членов объекта Application действуют глобально, а не на отдельные документы. Обращение к одним свойствам обычно требует единственной строки кода, а доступ к другим - более сложного кода.

  • ActiveWindow Возвращает объект Window, представляющий окно, которое находится в фокусе. Это свойство позволяет работать с любым окном, находящимся в фокусе. Ниже приведен пример кода, который создает новое окно на основе текущего документа, а затем вызывает метод Arrange объекта Window для размещения этих двух окон встык слева направо. Заметьте, что при вызове Arrange указывается перечислимое значение WdArrangeStyle.wdTiled.
    ' Visual Basic
    Friend Sub CreateNewWindowAndTile()
     ' Создаем новое окно на основе активного документа
     Dim wnd As Word.Window = _
       ThisApplication.ActiveWindow.NewWindow
     ' Размещаем два окна встык слева направо (tile)
     ThisApplication.Windows.Arrange( _
       Word.WdArrangeStyle.wdTiled)
    End Sub
     
    // C#
    public void CreateNewWindowAndTile()
    {
     // Создаем новое окно на основе активного документа
     Word.Window wnd =  ThisApplication.ActiveWindow.NewWindow();
     
     // Размещаем два окна встык слева направо
     Object value = Word.WdArrangeStyle.wdTiled;
     ThisApplication.Windows.Arrange(ref value);
    }
    

    Совет Метод Arrange, как и многие другие методы в Word, требует от разработчиков на C# передачи одного или нескольких параметров с ключевым словом ref. Это означает, что ваш параметр должен быть записан в переменную до передачи в метод. В каждом случае вы должны создавать переменную типа Object, присваивать ей значение, которое следует передать методу, и передавать эту переменную с ключевым словом ref. Соответствующие примеры вы встретите во многих разделах этого документа.

  • ActiveDocument Возвращает объект Document, представляющий активный документ или документ, который находится в фокусе.
  • ActivePrinter Возвращает или устанавливает имя активного принтера.
  • ActiveWindow Возвращает окно, которое находится в фокусе.
  • AutoCorrect Возвращает текущие параметры функции AutoCorrect, ее элементы и исключения. Это свойство предназначено только для чтения.
  • Caption Возвращает или устанавливает текст заголовка для указанного окна документа или приложения. Вот как с помощью свойства Caption вывести в строке заголовка окна документа или приложения текст "My New Caption":
    ' Visual Basic
    Friend Sub SetApplicationCaption()
     ' Изменяем текст в строке заголовка
     ThisApplication.Caption = "My New Caption"
    End Sub
     
    // C#
    public void SetApplicationCaption() 
    {
     // Изменяем текст в строке заголовка
     ThisApplication.Caption = "My New Caption";
    }
    
  • CapsLock Определяет, включен ли режим CapsLock, возвращает булево значение. Следующая процедура показывает состояние CapsLock:
    ' Visual Basic
    Friend Sub CapsLockOn()
     MessageBox.Show("CapsLock is " & _
       ThisApplication.CapsLock.ToString())
    End Sub
     
    // C#
    public void CapsLockOn() 
    {
     MessageBox.Show(ThisApplication.CapsLock.ToString());
    }
    
  • DisplayAlerts Позволяет указывать, как обрабатывать оповещения (alerts) при выполнении кода. Для этого используется перечислимое WdAlertLevel, которое содержит три значения: wdAlertsAll [отображаются все сообщения и оповещения (по умолчанию)], wdAlertsMessageBox (показываются только окна сообщений) и wdAlertsNone (ничего не отображается). Если вы установите DisplayAlerts в wdAlertsNone, ваш код будет выполняться, не показывая пользователю никаких сообщений и оповещений. Закончив, вы должны вернуть DisplayAlerts обратно в wdAlertsAll (обычно это делается в блоке Finally):
    ' Visual Basic
    Friend Sub DisplayAlerts()
     Try
      ' Отключаем отображение сообщений и оповещений
      ThisApplication.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone
      ' Ваш код выполняется без всяких оповещений
      ' . . .здесь что-то делаем
     Finally
      ' Вновь включаем показ оповещений
      ThisApplication.DisplayAlerts = Word.WdAlertLevel.wdAlertsAll
     End Try
    End Sub
     
    // C#
    public void DisplayAlerts() 
    {
     // Отключаем отображение сообщений и оповещений
     try 
     {
      ThisApplication.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
      // Ваш код выполняется без всяких оповещений
      // . . . здесь что-то делаем
     
     } 
     catch (Exception ex)
     {
      // Что-то делаем с исключением
     
     } 
     finally 
     {
      // Вновь включаем показ оповещений
      ThisApplication.DisplayAlerts = Word.WdAlertLevel.wdAlertsAll;
     }
    }
    
  • DisplayStatusBar Свойство для записи и чтения, возвращает булево значение, указывающее, отображается ли строка состояния (status bar). Возвращает True, если показывается, и False, если нет. Следующая процедура включает/выключает строку состояния:
    ' Visual Basic
    Friend Sub ToggleStatusBar()
     Dim bln As Boolean = (ThisApplication.DisplayStatusBar)
     ThisApplication.DisplayStatusBar = Not bln
    End Sub
     
    // C#
    public void ToggleStatusBar() 
    {
     // Переключатель признака отображения строки состояния
     bool bln = ThisApplication.DisplayStatusBar;
     ThisApplication.DisplayStatusBar = !bln;
    }
    
  • FileSearch Ищет файлы по абсолютному или относительному пути. Вы предоставляете критерии поиска, и FileSearch возвращает имена файлов, обнаруженных в наборе FoundFiles.
    ' Visual Basic 
    Public Sub ListAllDocFilesOnC()
     Dim str As String
     Dim sw As New StringWriter
     Try
      ThisApplication.System.Cursor = 
       Word.WdCursorType.wdCursorWait
      With ThisApplication.FileSearch
       .FileName = "*.doc"
       .LookIn = "C:\"
       .SearchSubFolders = True
       .Execute()
       For Each str In .FoundFiles
     sw.WriteLine(str)
       Next
      End With
      MessageBox.Show(sw.ToString())
     Finally
      ThisApplication.System.Cursor = 
       Word.WdCursorType.wdCursorNormal
     End Try
    End Sub
     
    // C#
    public void ListAllDocFilesOnC() 
    {
     try
     {
      ThisApplication.System.Cursor = Word.WdCursorType.wdCursorWait;
      StringWriter  sw = new StringWriter();
      Office.FileSearch fs = ThisApplication.FileSearch;
      fs.FileName = "*.doc";
      fs.LookIn = "C:\\";
      fs.SearchSubFolders = true;
      // Выбираем значения по умолчанию, необязательные в VBA:
      fs.Execute(Office.MsoSortBy.msoSortByFileName, 
       Office.MsoSortOrder.msoSortOrderAscending, true);
      foreach (String str in fs.FoundFiles)
      {
       sw.WriteLine(str);
      } 
      MessageBox.Show(sw.ToString());
     }
     finally
     {
      ThisApplication.System.Cursor =   
     Word.WdCursorType.wdCursorNormal;
       }
    }
    

    Совет Обратите внимание в этом примере на то, что разработчикам на Visual Basic .NET не требуется передавать все параметры в метод Execute, так как они необязательные. Однако разработчикам на C# придется передавать абсолютно все параметры. В этом случае вы должны предоставлять значения, соответствующие значениям по умолчанию. В случае параметров, передаваемых по ссылке, можно передавать значение Type.Missing, указывающее, что Word должен обрабатывать эти параметры так, будто вы вообще не передавали в них значений. Но в случае параметров, передаваемых по значению, вы должны указывать реальные значения. Чтобы выяснить значения по умолчанию для таких параметров, читайте справочный файл по Word VBA.

  • Path При использовании с объектом Application возвращает путь для текущего приложения:
    ' Visual Basic
    MessageBox.Show(ThisApplication.Path)
     
    // C#
    MessageBox.Show(ThisApplication.Path);
    

    Совет Чтобы получить путь для активного документа, используйте ThisDocument.Path.

  • Options Возвращает объект Options, который представляет параметры Word, позволяя разом устанавливать самые разнообразные параметры в вашем приложении. Многие из этих параметров (но не все!) доступны через диалоговое окно Tools | Options. Следующий фрагмент кода устанавливает значения свойств BackgroundSave и Overtype, а также свойств, заставляющих при печати автоматически обновлять любые поля Word и выводить скрытый текст и коды полей.
    ' Visual Basic
    ' Устанавливаем различные параметры приложения
    With ThisApplication.Options
     .BackgroundSave = True
     .Overtype = True
     .UpdateFieldsAtPrint = True
     .PrintHiddenText = True
     .PrintFieldCodes = True
    End With
     
    // C#
    // Устанавливаем различные параметры приложения
    Word.Options options = ThisApplication.Options;
     
    options.BackgroundSave = true;
    options.Overtype = true;
    options.UpdateFieldsAtPrint = true;
    options.PrintHiddenText = true;
    options.PrintFieldCodes = true;
    
  • Selection Объект только для чтения, представляющий выделенный фрагмент (или курсор ввода). Объект Selection будет детально описан позже.
  • UserName Возвращает или устанавливает имя пользователя. Следующая процедура показывает имя текущего пользователя, устанавливает свойство UserName в "Dudley" и выводит новое значение UserName. Затем код восстанавливает исходный UserName.
    ' Visual Basic
    Friend Sub ChangeUserName()
     Dim str As String = ThisApplication.UserName
     MessageBox.Show(str)
     ' Изменяем UserName
     ThisApplication.UserName = "Dudley"
     MessageBox.Show(ThisApplication.UserName)
     ' Восстанавливаем исходный UserName
     ThisApplication.UserName = str
    End Sub
     
    // C#
    public void ChangeUserName() 
    {
     string  str = ThisApplication.UserName;
     MessageBox.Show(str);
     
     // Изменяем UserName
     ThisApplication.UserName = "Dudley";
     MessageBox.Show(ThisApplication.UserName);
     // Восстанавливаем исходный UserName
     ThisApplication.UserName = str;
    }
    
  • Visible Свойство для чтения и записи, отображает или скрывает окно самого Word. Пока свойство Visible равно False, все открытые окна Word скрыты; при этом кажется, будто Word и все документы закрыты. Поэтому, если вы устанавливаете свойство Visible в False, не забудьте присвоить ему True по завершении своей процедуры. В следующем примере кода это делается в блоке Finally обработчика исключений Try/Catch:
    ' Visual Basic
    Try
     ThisApplication.Visible = False
     ' Здесь работаем в невидимом режиме
     
    Catch ex As Exception
     ' Здесь должен быть код вашего обработчика исключений
     
    Finally
     ThisApplication.Visible = True
    End Try
     
    // C#
    try 
    {
     ThisApplication.Visible = false;
     // Здесь работаем в невидимом режиме
    } 
    catch (Exception ex)
    {
     // Здесь должен быть код вашего обработчика исключений
    } 
    finally 
    {
     ThisApplication.Visible = true;
    }
    

Методы Application

У объекта Application есть несколько методов, удобных для выполнения операций с приложением Word. Работа с методами Application аналогична работе с его свойствами. Для операций с самим приложением используйте следующие методы.

  • CheckSpelling Проверяет провописание в строке текста. Возвращает True, если ошибки найдены, и False, если их нет. Этот метод не сообщает, какие именно ошибки обнаружены, и не позволяет исправить их, но удобен, если вы хотите просто проверить какой-то текст на наличие орфографических ошибок и узнать, есть в нем ошибки или нет. Следующий код проверяет строку "Speling erors here" и выводит результат в MessageBox.
    ' Visual Basic
    Friend Sub SpellCheckString()
     ' Проверяет указанную строку на орфографические ошибки
     Dim str As String = "Speling erors here."
     If ThisApplication.CheckSpelling(str) Then
      MessageBox.Show(String.Format("No errors in ""{0}""", str))
     Else
      MessageBox.Show(String.Format( _
     """{0}"" is spelled incorrectly", str))
     End If
    End Sub
     
    // C#
    public void SpellCheckString() 
    {
     // Проверяет указанную строку на орфографические ошибки
     string  str = "Speling erors here.";
     
     Object CustomDictionary = Type.Missing;
     Object IgnoreUppercase = Type.Missing;
     Object MainDictionary = Type.Missing;
     Object CustomDictionary2 = Type.Missing;
     Object CustomDictionary3 = Type.Missing;
     Object CustomDictionary4 = Type.Missing;
     Object CustomDictionary5 = Type.Missing;
     Object CustomDictionary6 = Type.Missing;
     Object CustomDictionary7 = Type.Missing;
     Object CustomDictionary8 = Type.Missing;
     Object CustomDictionary9 = Type.Missing;
     Object CustomDictionary10 = Type.Missing;
     
     // Метод CheckSpelling принимает массу необязательных
     // параметров
     if ( ThisApplication.CheckSpelling(str, ref CustomDictionary, 
      ref IgnoreUppercase, ref MainDictionary, ref CustomDictionary2,
      ref CustomDictionary3, ref CustomDictionary4, 
      ref CustomDictionary5, ref CustomDictionary6, 
      ref CustomDictionary7, ref CustomDictionary8, 
      ref CustomDictionary9, ref CustomDictionary10) ) 
     {
      MessageBox.Show(String.Format("No errors in \"{0}\"", str));
     } 
     else 
     {
      MessageBox.Show(
       String.Format("\"{0}\" is spelled incorrectly", str));
     }
    }
    

    Совет Это еще один пример тому, насколько разработчикам на Visual Basic .NET легче, чем разработчикам на C#. Метод CheckSpelling принимает единственный строковый параметр и целый набор необязательных параметров. Из-за этого разработчикам на C# приходится передавать методу целую серию переменных по ссылке - в данном случае группу переменных с одинаковым значением Type.Missing. Наверное, при неоднократном вызове подобных методов удобнее создать вспомогательный класс - оболочку для вызова метода. Такой класс мог бы включать методы, которые предоставляют доступ лишь к наиболее полезным параметрам Word-метода.

  • Help Отображает диалоговые окна Help. Чтобы выбрать конкретное окно, укажите одно из перечислимых значений WdHelpType:
  • WdHelp - выводит основное диалоговое окно Help в Microsoft Word;
  • WdHelpAbout - выводит диалоговое окно, доступное в UI по команде Help | About Microsoft Word;
  • WdHelpSearch - выводит основное диалоговое окно Help с Answer Wizard.

    Следующий код выведет на экран диалоговое окно About Microsoft Word:

    ' Visual Basic
    Friend Sub DisplayHelpAbout()
     ThisApplication.Help(Word.WdHelpType.wdHelpAbout)
    End Sub
     
    // C#
    public void DisplayHelpAbout() 
    {
     Object value = Word.WdHelpType.wdHelpAbout;
     ThisApplication.Help(ref value);
    }
    
  • Move Перемещает основное окно приложения на основе обязательных целочисленных аргументов Left и Top.
  • Resize Изменяет размеры основного окна приложения на основе обязательных аргументов Width и Height (в точках). Вот пример кода, который перемещает окно приложения в левый верхний угол экрана и изменяет размеры этого окна:
    ' Visual Basic
    Friend Sub MoveAndResizeWindow()
     ' Этот код не сработает, если окно развернуто во весь экран
     ' или свернуто
     ThisApplication.ActiveWindow.WindowState = _
       Word.WdWindowState.wdWindowStateNormal
     
     ' Позиция в левом верхнем углу
     ThisApplication.Move(0, 0)
     
     ' Изменяем размеры на 300 x 600 точек
     ThisApplication.Resize(300, 600)
    End Sub
     
    // C#
    public void MoveAndResizeWindow() 
    {
     // Этот код не сработает, если окно развернуто во весь экран
     // или свернуто
     ThisApplication.ActiveWindow.WindowState = 
      Word.WdWindowState.wdWindowStateNormal;
     
     // Позиция в левом верхнем углу
     ThisApplication.Move(0, 0);
     
     // Изменяем размеры на 300 x 600 точек
     ThisApplication.Resize(300, 600);
    }
    
  • Quit Выход из Word. При этом вы можете (необязательно) передать одно из значений из перечислимого WdSaveOptions: wdSaveChanges, wdPromptToSaveChanges или wdDoNotSaveChanges. Следующий фрагмент кода показывает все три варианта выхода из Word:
    ' Visual Basic
    ' Автоматически сохраняем все изменения
    ThisApplication.Quit(Word.WdSaveOptions.wdSaveChanges)
     
    ' Выводим запрос на сохранение изменений
    ThisApplication.Quit(Word.WdSaveOptions.wdPromptToSaveChanges)
     
    ' Выходим без сохранения изменений
    ThisApplication.Quit(Word.WdSaveOptions.wdDoNotSaveChanges)
     
    // C#
    // Автоматически сохраняем все изменения
    Object saveChanges = Word.WdSaveOptions.wdSaveChanges;
    Object originalFormat = Type.Missing;
    Object routeDocument = Type.Missing;
    ThisApplication.Quit(ref saveChanges, 
     ref originalFormat, ref routeDocument);
     
    // Выводим запрос на сохранение изменений
    saveChanges = Word.WdSaveOptions.wdPromptToSaveChanges;
    originalFormat = Type.Missing;
    routeDocument = Type.Missing;
    ThisApplication.Quit(ref saveChanges, 
     ref originalFormat, ref routeDocument);
     
    // Выходим без сохранения изменений
    saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
    originalFormat = Type.Missing;
    routeDocument = Type.Missing;
    ThisApplication.Quit(ref saveChanges, 
     ref originalFormat, ref routeDocument);
    

    Совет Метод Application.Quit - еще один пример из списка методов, требующих особого обращения в C#. В данном случае метод требует передачи трех параметров только по ссылке.

  • SendFax Запускает Fax Wizard, как показано на рис. 8. После этого пользователь может выполнить нужную операцию под руководством Fax Wizard.
    ' Visual Basic
    Friend Sub LaunchFaxWizard()
     ThisApplication.SendFax()
    End Sub
     
    // C#
    public void LaunchFaxWizard() 
    {
     ThisApplication.SendFax();
    }
    

Рис. 8. Fax Wizard можно запустить вызовом метода SendFax

Использование встроенных диалоговых окон в Word

При работе с Word время от времени возникает необходимость в отображении диалоговых окон для приема пользовательского ввода. Хотя вы можете создавать свои диалоговые окна, зачастую удобнее пользоваться встроенными в Word, доступ к которым открывается через набор Dialogs объекта Application. Это позволяет обращаться более чем к 200 встроенным диалоговым окнам Word; при этом используются значения перечислимого WdWordDialog. Чтобы задействовать объект Dialog в своем коде, объявите его как Word.Dialog:

' Visual Basic
Dim dlg As Word.Dialog
 
// C#
Word.Dialog dlg;

Чтобы указать интересующий вас диалог Word, присвойте переменной одно из значений, соответствующее массиву доступных диалоговоых окон:

' Visual Basic
dlg = ThisApplication.Dialogs(Word.WdWordDialog.wdDialogFileNew)
 
// C#
Dlg = ThisApplication.Dialogs[Word.WdWordDialog.wdDialogFileNew];

Создав переменную Dialog, вы можете использовать ее методы. Метод Show выводит диалоговое окно так, будто пользователь вручную выбрал его из меню Word. Следующая процедура показывает диалоговое окно File New:

' Visual Basic
Friend Sub DisplayFileNewDialog()
 Dim dlg As Word.Dialog
 dlg = ThisApplication.Dialogs( _
   Word.WdWordDialog.wdDialogFileNew)
 dlg.Show()
End Sub
 
// C#
public void DisplayFileNewDialog() 
{
 Object timeOut = Type.Missing;
 
 Word.Dialog dlg;
 dlg = ThisApplication.Dialogs[Word.WdWordDialog.wdDialogFileNew];
  dlg.Show(ref timeOut);
}

Совет Метод Show принимает параметр TimeOut, указывающий число миллисекунд (мс), по истечении которых диалоговое окно будет автоматически закрыто. В Visual Basic .NET этот параметр можно просто проигнорировать, а в C# придется передать Type.Missing по ссылке, чтобы согласиться со значением по умолчанию (без ожидания).

Еще одно эффективное применение диалогов Word - проверка правописания в документе. Следующая процедура запускает средство проверки правописания для активного документа, используя перечислимое значение wdDialogToolsSpellingAndGrammar:

' Visual Basic
Friend Sub DisplaySpellCheckDialog()
 Dim dlg As Word.Dialog
 dlg = ThisApplication.Dialogs( _
   Word.WdWordDialog.wdDialogToolsSpellingAndGrammar)
  dlg.Show()
End Sub
 
// C#
public void DisplaySpellCheckDialog() 
{
 Object timeOut = Type.Missing;
 Word.Dialog dlg;
 dlg = ThisApplication.Dialogs
  [Word.WdWordDialog.wdDialogToolsSpellingAndGrammar];
 dlg.Show(ref timeOut);
}

Методы Word.Dialog

Кроме метода Show, есть еще три метода, которые можно использовать с диалоговыми окнами Word: Display, Update и Execute.

  • Display Отображает указанный встроенный диалог Word до тех пор, пока его не закроет пользователь или не истечет заданное время. Метод не выполняет никаких операций, которые выполнил бы данный диалог в обычных условиях. Вы можете указать необязательный таймаут (период ожидания). Код в следующей процедуре использует метод Display и передает ему необязательное значение Timeout, чтобы диалоговое окно UserInfo появилось на экране примерно на три секунды. Если пользователь самостоятельно не закроет это окно, оно будет закрыто автоматически:
    ' Visual Basic
    Friend Sub DisplayUserInfoDialog()
     Dim dlg As Word.Dialog
     dlg = ThisApplication.Dialogs( _
       Word.WdWordDialog.wdDialogToolsOptionsUserInfo)
     dlg.Display(3000)
    End Sub
     
    // C#
    public void DisplayUserInfoDialog() 
    {
     Word.Dialog dlg;
     Object timeout = 3000;
     dlg = ThisApplication.Dialogs[
      Word.WdWordDialog.wdDialogToolsOptionsUserInfo];
     dlg.Display(ref timeout);
    }
    

    Совет Хотя у разработчиков на C# может появиться соблазн передать литеральные параметры как простые, делать этого не следует, так как иначе не удастся скомпилировать код. Вместо этого разработчики на C# должны создать переменную типа Object, поместить в нее литеральное значение и передать переменную по ссылке.

    Если вас интересует, какой кнопкой пользователь закрыл диалоговое окно, вы можете получить результат от метода Display в виде переменной типа Integer и предпринять в своем коде действия, соответствующие выбранной кнопке. Например, пользователь редактирует имя и фамилию в диалоговом окне UserInfo. Если он после этого щелкает кнопку OK, внесенные изменения должны быть сохранены, а если он нажимает кнопку Cancel - отменены.

    ' Visual Basic
    Dim returnValue As Integer = dlg.Display()
     
    // C#
    Integer returnValue = dlg.Display();
    

    Возможные значения, возвращаемые методом, перечислены в табл. 1.

    Табл. 1. Возвращаемые значения

     

    Значение Нажатая кнопка
    -2 Кнопка Close
    -1 Кнопка OK
    0 (ноль) Кнопка Cancel
    > 0 Командная кнопка: 1 - первая кнопка, 2 - вторая и т. д.

    Однако, если вы не предпримете явных действий для сохранения изменений, внесенных через это диалоговое окно, выбор кнопки пользователем не будет иметь никакого значения; все изменения будут отброшены. Поэтому вы должны вызвать метод Execute для явного применения изменений, внесенных через диалоговое окно.

  • Execute Если вы просто вызовете метод Display и пользователь изменит какие-то значения в диалоговом окне, эти изменения не будут сохранены. После вызова Display вы должны вызвать метод Execute, чтобы любые изменения, внесенные пользователем, вступили в силу. В отличие от метода Save, который сохраняет пользовательские изменения, без дополнительных действий с вашей стороны все изменения отбрасываются, даже если пользователь щелкает кнопку OK. Следующий код вызывает диалоговое окно UserInfo через Display, а затем проверяет значение, возвращаемое в переменной типа Integer. Если пользователь щелкает кнопку OK (возвращается значение -1), код вызывает метод Execute для применения этих изменений:
    ' Visual Basic
    Friend Sub DisplayExecuteDialog()
     Dim dlg As Word.Dialog
     dlg = ThisApplication.Dialogs( _
       Word.WdWordDialog.wdDialogToolsOptionsUserInfo)
     ' Ждем результатов 10 секунд
     Dim int As Integer = dlg.Display(10000)
     ' Нажал ли пользователь OK?
     If int = -1 Then
      dlg.Execute()
     End If
    End Sub
     
    // C#
    public void DisplayExecuteDialog() 
    {
     Word.Dialog dlg;
     dlg = ThisApplication.Dialogs[
      Word.WdWordDialog.wdDialogToolsOptionsUserInfo];
     
     // Ждем результатов 10 секунд
     Object timeout = 10000;
     int value = dlg.Display(ref timeout);
     
     // Нажал ли пользователь OK?
     if (value == -1) 
     {
     dlg.Execute();
     }
    }
    

    Совет Вы можете получить значение Name, введенное в диалоговом окне UserInfo, через свойство ThisApplication.UserName.

  • Update Используйте метод Update, когда нужно быть уверенным, что диалоговое окно показывает корректные значения. Поскольку вы можете программно модифицировать содержимое диалогового окна (даже после получения ссылки на диалоговое окно), перед отображением следует обновить его содержимое. (Об использовании диалоговых окон Word в скрытом режиме см. следующий раздел - именно в этом случае вам понадобится данный метод.)

Модификация значений диалога
Из-за специфики диалоговых окон Word все свойства различных диалогов, которые соответствуют значениям элементов управления на формах, доступны только в период выполнения. То есть, когда Word загружает диалоговое окно, он создает различные свойства и добавляет их в период выполнения к соответствующим объектам. Это затрудняет разработчикам написание строго типизированного кода (как в C# или в Visual Basic .NET при наличии Option Strict On).
Например, диалоговое окно Page Setup (представляемое перечислимым значением WdWordDialog.wdDialogFilePageSetup) поддерживает ряд свойств, относящихся к настройке параметров страниц, в том числе PageWidth, PageHeight и т. д. Наверное, вы предпочли бы писать код для доступа к этим свойствам в таком стиле:

' Visual Basic
Dim dlg As Word.Dialog
dlg = ThisApplication.Dialogs( _
  Word.WdWordDialog.wdDialogFilePageSetup)
dlg.PageWidth = 3.3
dlg.PageHeight = 6.6

Увы, этот код просто не удастся скомпилировать в Visual Basic .NET с Option Strict On или в C# - свойства PageWidth и PageHeight остаются неопределенными в объекте Dialog до периода выполнения.

У вас есть два варианта: вы можете либо создать файл на Visual Basic, в начале которого указано Option Strict Off, либо пойти по пути позднего связывания. (Конечно, вы могли бы использовать пространство имен System.Reflection и самостоятельно реализовать позднее связывание.) Метод CallByName, предоставляемый сборкой Microsoft.VisualBasic, позволяет указать в виде строки имя свойства, с которым вы хотите взаимодействовать, а также значение этого свойства и нужное вам действие. Этот метод выручит вас независимо от того, на каком языке вы пишете код - на Visual Basic .NET или C#. Разработчикам на C#, конечно, придется добавить ссылку на сборку Microsoft.VisualBasic, чтобы воспользоваться этим приемом.

После этого вы сможете писать примерно такой код:

' Visual Basic
dlg = ThisApplication.Dialogs( _
  Word.WdWordDialog.wdDialogFilePageSetup)
 
CallByName(dlg, "PageWidth", CallType.Let, 3.3)
CallByName(dlg, "PageHeight", CallType.Let, 6)
 
// C#
using VB = Microsoft.VisualBasic;
 
// Затем внутри какой-то процедуры,:
dlg = ThisApplication.Dialogs
 [Word.WdWordDialog.wdDialogFilePageSetup];
 
VB.Interaction.CallByName(dlg, "PageWidth", 
 VB.CallType.Let, 3.3);
VB.Interaction.CallByName(dlg, "PageHeight", 
 VB.CallType.Let, 6);

Это решение не идеально - код труден в написании и восприятии и, кроме того, требует от разработчиков на C# пользоваться методами из Visual Basic (что может оказаться драконовским решением), зато оно дает возможность работать с иначе недоступным набором свойств.

Проект-пример включает процедуру, которая модифицирует параметры страниц для текущего документа, используя диалоговое окно Page Setup. Заметьте, что этот код вызывает метод Execute класса Dialog и само окно никогда не отображает, - настраивать большой набор свойств таким способом гораздо проще, чем самостоятельно обращаться ко множеству объектов.

' Visual Basic
using VB = Microsoft.VisualBasic;
 
Public Sub HiddenPageSetupDialog()
 Dim dlg As Word.Dialog
 dlg = ThisApplication.Dialogs( _
   Word.WdWordDialog.wdDialogFilePageSetup)
 
 CallByName(dlg, "PageWidth", CallType.Let, ConvertToInches(3.3))
 CallByName(dlg, "PageHeight", CallType.Let, ConvertToInches(6))
 CallByName(dlg, "TopMargin", CallType.Let, ConvertToInches(0.72))
 CallByName(dlg, "BottomMargin", CallType.Let, _
   ConvertToInches(0.72))
 CallByName(dlg, "LeftMargin", CallType.Let, _
   ConvertToInches(0.66))
  CallByName(dlg, "RightMargin", CallType.Let, _
   ConvertToInches(0.66))
 CallByName(dlg, "Orientation", CallType.Let, _
   Word.WdOrientation.wdOrientPortrait)
 CallByName(dlg, "DifferentFirstPage", CallType.Let, False)
 CallByName(dlg, "HeaderDistance", CallType.Let, _
   ConvertToInches(0.28))
 ' Используйте свойство ApplyPropsTo, чтобы определить,
 ' к чему применяются новые настройки:
 ' 0 = к данному разделу
 ' 1 = к документу от этой точки в направлении вперед
 ' 2 = к выбранным разделам
 ' 3 = к выделенному тексту
 ' 4 = ко всему документу
 CallByName(dlg, "ApplyPropsTo", CallType.Let, 0)
 dlg.Execute()
End Sub
 
Private Function ConvertToInches(ByVal value As Double) As String
  Return String.Format("{0}""", value)
End Function
 
// C#
public void HiddenPageSetupDialog()
{
 Word.Dialog dlg;
 dlg = ThisApplication.Dialogs[
  Word.WdWordDialog.wdDialogFilePageSetup];
 
 VB.Interaction.CallByName(dlg, "PageWidth", VB.CallType.Let, 
  ConvertToInches(3.3));
 VB.Interaction.CallByName(dlg, "PageHeight", VB.CallType.Let, 
  ConvertToInches(6));
 VB.Interaction.CallByName(dlg, "TopMargin", VB.CallType.Let, 
  ConvertToInches(0.72));
 VB.Interaction.CallByName(dlg, "BottomMargin", VB.CallType.Let, 
  ConvertToInches(0.72));
 VB.Interaction.CallByName(dlg, "LeftMargin", VB.CallType.Let, 
  ConvertToInches(0.66));
 VB.Interaction.CallByName(dlg, "RightMargin", VB.CallType.Let, 
  ConvertToInches(0.66));
 VB.Interaction.CallByName(dlg, "Orientation", VB.CallType.Let, 
  Word.WdOrientation.wdOrientPortrait);
 VB.Interaction.CallByName(dlg, "DifferentFirstPage", 
  VB.CallType.Let, false);
 VB.Interaction.CallByName(dlg, "HeaderDistance", VB.CallType.Let, 
  ConvertToInches(0.28));
 // Используйте свойство ApplyPropsTo, чтобы определить,
 // к чему применяются новые настройки:
 // 0 = к данному разделу
 // 1 = к документу от этой точки в направлении вперед
 // 2 = к выбранным разделам
 // 3 = к выделенному тексту
 // 4 = ко всему документу
 VB.Interaction.CallByName(dlg, "ApplyPropsTo", VB.CallType.Let, 
  0);
 dlg.Execute();
}
private String ConvertToInches(double value) 
{
  return String.Format("{0}\"", value);
}

Совет Единицы измерения в Word иногда приводят к путанице. В большинстве случаев применяются значения в пунктах (points) (1/72"), но вы всегда можете переопределить единицы, передав строку вроде "3"" (она задает три дюйма). В примере вызывается метод ConvertToInches, который обрабатывает символ кавычки. Странно то, что свойства PageWidth и PageHeight работают с единицами измерения, заданными пользователем как единицы по умолчанию, тогда как остальные свойства в этом примере требуют либо указания пунктов, либо строки, содержащей значение - индикатор единицы измерения. Ввиду этого в странах, где используются дюймы, вызов ConvertToInches для первых двух свойств в примере необязателен. Однако, даже если этот вызов излишний, он ничему не повредит.

Решая, использовать встроенные диалоговые окна или нет, примите во внимание свой объем работ. Если вы настраиваете лишь несколько свойств единственного объекта, то, по-видимому, проще работать с этим объектом напрямую. Если же вам требуется выводить UI для взаимодействия с пользователями, лучший вариант - задействовать соответствующее диалоговое окно.

Совет Если вам нужны все возможности Word-объекта Dialog, одной справочной системы Word недостаточно. Более подробные сведения вы найдете в справочной файле по WordBasic от Word 95. Ищите этот файл на www.microsoft.com по ключевым словам "Word 95 WordBasic Help File".

Объект Document

Один из основных объектов в программировании Word - Document или его содержимое. Когда вы работаете с каким-то документом в Word, он считается активным, и на него можно ссылаться через свойство ActiveDocument объекта Application. Все Word-объекты Document также являются членами набора Documents объекта Application; этот набор включает все открытые документы. Объект Document позволяет работать с единственным документом, а набор Documents - со всеми открытыми документами. У классов Application и Document много общих членов, поэтому операции над документами можно выполнять как на уровне Application, так и на уровне Document.

К наиболее распространенным операциям над документами относятся:

  • создание и открытие документов;
  • добавление, поиск и замена текста;
  • печать.

Наборы объекта Document

Документ состоит из символов, упорядоченных в слова, слова - в предложения, а те - в абзацы, которые в свою очередь могут быть упорядочены в разделы (sections). В каждом разделе свои верхние и нижние колонтитулы (headers and footers). Объект Document включает следующие наборы:

  • Characters;
  • Words;
  • Sentences;
  • Paragraphs;
  • Sections;
  • Headers/Footers.

Ссылки на документы

Вы можете ссылаться на объект Document как на член набора Documents по индексу. Индекс определяет местонахождение объекта Document в наборе Documents, причем индексы отсчитываются от 1, как и все наборы в Word. Следующий фрагмент кода присваивает объектной переменной ссылку на первый объект Document в наборе Documents:

' Visual Basic
Dim doc As Word.Document = _
  DirectCast(ThisApplication.Documents(1), Word.Document)
 
// C#
Word.Document doc = (Word.Document) ThisApplication.Documents[1];

Кроме того, на документ можно ссылаться по имени, что обычно удобнее, если вам нужно работать с определенным документом. Вряд ли вы будете часто ссылаться на документ по индексу, так как это значение может изменяться по мере открытия и закрытия других документов. Следующий фрагмент кода присваивает объектной переменной ссылку на документ по имени MyDoc.doc:

' Visual Basic
Dim doc As Word.Document = _
  DirectCast(ThisApplication.Documents("MyDoc.doc"), Word.Document)
 
// C#
Word.Document doc = 
 (Word.Document) ThisApplication.Documents["MyDoc.doc"];

Если вам нужно сослаться на активный документ (документ, находящийся в фокусе), используйте свойство ActiveDocument объекта Application. Это свойство уже создано за вас в проекте Visual Studio .NET, поэтому ваш код будет эффективнее при ссылках на активный документ по ссылке ThisDocument. Вот пример кода, получающего имя активного документа:

' Visual Basic
Dim str As String = ThisDocument.Name
 
// C#
String str = ThisDocument.Name;

Создание, открытие и закрытие документов

Ссылка на объект ThisDocument в вашем проекте Word открывает вам доступ ко всем членам объекта Document, что позволяет работать с его методами и свойствами применительно к активному документу. Первый шаг в работе с Document - открытие существующего документа Word или создание нового.

Создание нового документа Word

Создавая новый документ Word, вы добавляете его в набор Documents объекта Application, где хранятся открытые документы Word. Поэтому для создания нового документа следует вызвать метод Add. Это равносильно щелчку кнопки New Blank Document на панели инструментов.

' Visual Basic
' Создание нового документа на основе Normal.dot
ThisApplication.Documents.Add()
 
// C#
// Создание нового документа на основе Normal.dot
Object template = Type.Missing;
Object newTemplate = Type.Missing;
Object documentType = Type.Missing;
Object visible = Type.Missing; 
 
ThisApplication.Documents.Add( 
  ref template, ref newTemplate, ref documentType, ref visible);

Совет Метод Documents.Add принимает до четырех необязательных параметров: имя шаблона, имя нового шаблона, тип документа и признак видимости нового документа. В C#, чтобы использовать значения по умолчанию для этих параметров, приходится передавать Type.Missing по ссылке.

У метода Add есть необязательный аргумент Template для создания нового документа на основе шаблона, отличного от Normal.dot. В этом случае вы должны предоставить полное имя файла (вместе с путем) этого шаблона.

' Visual Basic
' Создание нового документа на основе собственного шаблона
ThisApplication.Documents.Add( _
 "C:\Test\MyTemplate.Dot")
 
// C#
// Создание нового документа на основе собственного шаблона
Object template = @"C:\Test\MyTemplate.Dot";
Object newTemplate = Type.Missing;
Object documentType = Type.Missing;
Object visible = Type.Missing; 
 
ThisApplication.Documents.Add( 
 ref template, ref newTemplate, ref documentType, ref visible);

Этот код дает тот же результат, что и при выборе File | New и указании шаблона с помощью панели инструментов New Document. Задавая в коде аргумент Template, можно быть уверенным, что все документы будут создаваться на основе указанного шаблона.

Открытие существующего документа

Для этого предназначен метод Open. Его базовый синтаксис предельно прост: вызывая Open, вы указываете полный путь и имя файла. Этот метод также принимает ряд необязательных аргументов, например пароль или флаг, сообщающий, что документ должен быть только для чтения. Следующий код открывает документ, передавая лишь один из нескольких необязательных параметров. Разумеется, в коде на C# нужно передавать все параметры, но реальное значение требуется только для параметра FileName:

' Visual Basic
ThisApplication.Documents.Open("C:\Test\MyNewDocument")
 
// C#
Object filename = @"C:\Test\MyNewDocument";
Object confirmConversions = Type.Missing;
Object readOnly = Type.Missing;
Object addToRecentFiles = Type.Missing;
Object passwordDocument = Type.Missing;
Object passwordTemplate = Type.Missing;
Object revert = Type.Missing;
Object writePasswordDocument = Type.Missing;
Object writePasswordTemplate = Type.Missing;
Object format = Type.Missing;
Object encoding = Type.Missing;
Object visible = Type.Missing;
Object openConflictDocument = Type.Missing;
Object openAndRepair  = Type.Missing;
Object documentDirection = Type.Missing;
Object noEncodingDialog = Type.Missing;
 
ThisApplication.Documents.Open(ref filename, 
 ref confirmConversions, ref readOnly, ref addToRecentFiles, 
 ref passwordDocument, ref passwordTemplate, ref revert, 
 ref writePasswordDocument, ref writePasswordTemplate, 
 ref format, ref encoding, ref visible, ref openConflictDocument, 
 ref openAndRepair , ref documentDirection, ref noEncodingDialog);

Сохранение документов

Сохранять и закрывать документы можно несколькими способами - в зависимости от того, какого результата вы хотите добиться. Для сохранения и закрытия документа вы вызываете методы Save и Close соответственно. Они дают разные результаты в зависимости от того, как именно вы их используете. Если они применяются к объекту Document, их действие распространяется только на соответствущий документ. А если они применяются к набору Documents - на все открытые документы.

  • Сохранение всех документов Метод Save сохраняет изменения во всех открытых документах, когда применяется к объекту Documents. При этом у вас есть два варианта. Если вы просто вызываете Save набора Documents, пользователю выводится запрос на сохранение всех файлов.
    ' Visual Basic
    ThisApplication.Documents.Save()
     
    // C#
    Object noPrompt = Type.Missing;
    Object originalFormat = Type.Missing;
     
    ThisApplication.Documents.Save(ref noPrompt, ref originalFormat);
    
  • Следующий код устанавливает параметр NoPrompt в True и сохраняет все открытые документы без участия пользователя.
    ' Visual Basic
    ThisApplication.Documents.Save(NoPrompt:=True)
     
    // C#
    Object noPrompt = true;
    Object originalFormat = Type.Missing;
    ThisApplication.Documents.Save(ref noPrompt, ref originalFormat);
    

    Совет По умолчанию NoPrompt равен False, поэтому, если вы вызываете Save без NoPrompt в Visual Basic .NET и с указанием вместо него Type.Missing в C#, пользователю выводится запрос на сохранение.

  • Сохранение единственного документа Метод Save сохраняет изменения в заданном объекте Document. Следующий фрагмент кода показывает два варианта сохранения активного документа:
    ' Visual Basic
    ' Сохраняем активный документ так…
    ThisDocument.Save()
     
    ' …или так
    ThisApplication.ActiveDocument.Save()
     
    // C#
    // Сохраняем активный документ так…
    ThisDocument.Save();
    // …или так
    ThisApplication.ActiveDocument.Save();
    
  • Если вы не знаете точно, активен ли сохраняемый вами документ, ссылайтесь на него по имени. Например:
    ' Visual Basic
    ThisApplication.Documents("MyNewDocument.doc").Save()
     
    // C#
    Object file = "MyNewDocument.doc";
    ThisApplication.Documents.get_Item(ref file).Save();
    

    Совет Хотя разработчики на Visual Basic .NET могут получать элементы различных наборов, используя стандартный синтаксис Visual Basic (вызывая свойство Item или пропуская этот необязательный вызови предоставляя индекс или имя), разработчики на C# этого делать, как правило, не могут. Обычно они должны вызывать скрытый метод get_Item с передачей индекса или имени по ссылке, как в предыдущем примере. Разработчики на C# могут обращаться напрямую лишь к элементам массивов (как в массиве Dialogs, уже показанном в одном из примеров).

  • Альтернативный синтаксис - использование индекса документа, но он ненадежен по двум причинам. Во-первых, нет уверенности, что индекс вашего документа не изменится, а во-вторых, если документ, на который вы ссылаетесь, еще ни разу не сохранялся, появится диалоговое окно Save As. Следующий код сохраняет первый документ в наборе Documents:
    ' Visual Basic
    ThisApplication.Documents(1).Save()
     
    // C#
    Object file = 1;
    ThisApplication.Documents.get_Item(ref file).Save();
    
  • SaveAs Метод SaveAs позволяет сохранить документ под другим именем файла. Он требует передачи лишь нового имени файла, а остальные аргументы необязательны. Следующая процедура сохраняет документ в соответствии с "зашитым" в код путем и именем файла. Если файл с таким именем в данной папке уже есть, он "молча" перезаписывается. (Заметьте, что метод SaveAs принимает несколько необязательных параметров, о каждом из которых нужно позаботиться, если вы используете C#.)
    ' Visual Basic
    ' Сохраняем документ. В реальном приложении следует проверять
    ' наличие одноименного файла. В данном случае любой
    ' ранее существовавший документ просто перезаписывается.
    ThisDocument.SaveAs("c:\test\MyNewDocument.doc")
     
    // C#
    // Сохраняем документ. В реальном приложении следует проверять
    // наличие одноименного файла. В данном случае любой
    // ранее существовавший документ просто перезаписывается.
    Object fileName = @"C:\Test\MyNewDocument.doc";
    Object fileFormat = Type.Missing;
    Object lockComments = Type.Missing;
    Object password = Type.Missing;
    Object addToRecentFiles = Type.Missing;
    Object writePassword = Type.Missing;
    Object readOnlyRecommended = Type.Missing;
    Object embedTrueTypeFonts = Type.Missing;
    Object saveNativePictureFormat = Type.Missing;
    Object saveFormsData = Type.Missing;
    Object saveAsAOCELetter = Type.Missing;
    Object encoding = Type.Missing;
    Object insertLineBreaks = Type.Missing;
    Object allowSubstitutions = Type.Missing;
    Object lineEnding = Type.Missing;
    Object addBiDiMarks = Type.Missing;
     
    ThisDocument.SaveAs(ref fileName, ref fileFormat, ref lockComments, 
      ref password, ref addToRecentFiles, ref writePassword, 
      ref readOnlyRecommended, ref embedTrueTypeFonts, 
      ref saveNativePictureFormat, ref saveFormsData, 
      ref saveAsAOCELetter, ref encoding, ref insertLineBreaks, 
      ref allowSubstitutions, ref lineEnding, ref addBiDiMarks);
    

Закрытие документов

Метод Close позволяет не только закрывать документы, но и сохранять их. Вы можете закрывать документы индивидуально или все сразу.

  • Закрытие всех документов Применительно к набору Documents метод Close работает аналогично методу Save. При вызове без аргументов он предлагает пользователю сохранить изменения в любых несохраненных документах.
    ' Visual Basic
    ThisApplication.Documents.Close()
     
    // C#
    Object saveChanges = Type.Missing;
    Object originalFormat = Type.Missing;
    Object routeDocument = Type.Missing;
    ThisApplication.Documents.Close(ref saveChanges, 
     ref originalFormat, ref routeDocument);
    

    Как и Save, метод Close принимает необязательный аргумент SaveChanges, у которого есть перечислимое WdSaveOptions с тремя значениями: wdDoNotSaveChanges, wdPromptToSaveChanges и wdSaveChanges. В следующем примере показано, как закрыть все открытые документы с автоматическим сохранением или отбрасыванием изменений:

    ' Visual Basic
    ' Закрываем все документы с автоматическим сохранением
    ThisApplication.Documents.Close( _
      Word.WdSaveOptions.wdSaveChanges)
     
    ' Закрываем все документы с автоматическим отбрасыванием изменений
    ThisApplication.Documents.Close( _
      Word.WdSaveOptions.wdDoNotSaveChanges)
     
    // C#
    // Закрываем все документы с автоматическим сохранением
    Object saveChanges = Word.WdSaveOptions.wdSaveChanges;
    Object originalFormat = Type.Missing;
    Object routeDocument = Type.Missing;
    ThisApplication.Documents.Close(ref saveChanges, 
     ref originalFormat, ref routeDocument);
     
    // Закрываем все документы с автоматическим отбрасыванием изменений
    Object saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
    Object originalFormat = Type.Missing;
    Object routeDocument = Type.Missing;
    ThisApplication.Documents.Close(ref saveChanges, 
     ref originalFormat, ref routeDocument);
    

    Примечание Вызов метода Application.Quit закрывает Word. Но закрытие всех открытых документов не приводит к закрытию Word - он может быть завершен только явным образом.

  • Закрытие единственного документа Фрагменты кода, приведенные ниже, иллюстрируют, как закрыть активный документ без сохранения изменений и как закрыть документ MyNewDocument, автоматически сохранив изменения:
    ' Visual Basic
    ' Закрываем активный документ без сохранения изменений
    ThisDocument.Close( _
      Word.WdSaveOptions.wdDoNotSaveChanges)
     
    ' Закрываем MyNewDocument и "молча" сохраняем изменения
    ThisApplication.Documents("MyNewDocument.doc").Close( _
      Word.WdSaveOptions.wdSaveChanges)
     
    // C#
    // Закрываем активный документ без сохранения изменений
    Object saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
    Object originalFormat = Type.Missing;
    Object routeDocument = Type.Missing;
    ThisDocument.Close(ref saveChanges, 
     ref originalFormat, ref routeDocument);
     
    // Закрываем MyNewDocument и "молча" сохраняем изменения
    Object name = "MyNewDocument.doc";
    saveChanges = Word.WdSaveOptions.wdSaveChanges;
    originalFormat = Type.Missing;
    routeDocument = Type.Missing;
     
    Word.Document doc = ThisApplication.Documents.get_Item(ref name);
    ThisDocument.Close(ref saveChanges, 
     ref originalFormat, ref routeDocument);
    

Перечисление набора Documents

В большинстве случае вы работаете с индивидуальными документами, и потребности в перечислении всего набора Documents не возникает. Но бывают ситуации, в которых нужно проверять каждый открытый документ и в зависимости от результатов проверки выполнять некую операцию. В таких ситуациях вы можете использовать цикл For Each (в Visual Basic .NET) или foreach (в C#) для перебора всех документов. Внутри этого цикла вы выполняете операции над файлами, если соблюдается какое-то условие или условия. В данном примере код перебирает все открытые документы и, если документ еще не сохранен, сохраняет его.

Вот что делает код в процедуре-примере:

  • перебирает набор открытых документов;
  • проверяет значение свойства Saved каждого документа и сохраняет документ, если он еще не сохранен;
  • получает имя каждого сохраненного документа;
  • отображает имя каждого сохраненного документа в MessageBox или выводит сообщение о том, что сохранять какие-либо документы не требуется.
' Visual Basic
Public Sub SaveUnsavedDocuments()
 ' Перечисляем набор Documents
 Dim str As String
 Dim doc As Word.Document
 Dim sw As New StringWriter
 
 For Each doc In ThisApplication.Documents
  If Not doc.Saved Then
   ' Сохраняем документ
   doc.Save()
   sw.WriteLine(doc.Name)
  End If
 Next
 
 str = sw.ToString()
 If str = String.Empty Then
  str = "No documents need saving."
 End If
 MessageBox.Show(str, "SaveUnsavedDocuments")
End Sub
 
// C#
public void SaveUnsavedDocuments() 
{
 // Перечисляем набор Documents
 string  str;
 StringWriter  sw = new StringWriter();
 
 foreach (Word.Document doc in ThisApplication.Documents)
 {
  if (!doc.Saved ) 
  {
   // Сохраняем документ
   doc.Save();
   sw.WriteLine(doc.Name);
  }
 } 
 
 str = sw.ToString();
 if ( str == string.Empty ) 
 {
 str = "No documents need saving.";
 } 
 MessageBox.Show(str, "SaveUnsavedDocuments");
}

Объект Selection

Объект Selection представляет текущую выделенную область документа Word. Выполняя какую-либо операцию в пользовательском интерфейсе Word (например выделяя текст полужирным начертанием), вы выделяете текст, а затем применяете нужные параметры форматирования. Аналогичным образом вы используете в коде объект Selection: определяете выделенный фрагмент и выполняете операцию. Этот объект позволяет выделять, форматировать, манипулировать и печатать текст в документе.

Объект Selection всегда присутствует в документе. Если ничего не выделено, он представляет курсор ввода (insertion point). Поэтому, прежде чем пытаться что-то делать, важно понять, из чего состоит объект Selection.

Примечание У объектов Selection и Range много общих членов. Разница между этими объектами в том, что Selection ссылается на то, что выделено в UI, а Range не отображается (хоть это и возможно - вызовом его метода Select).

СоветИспользуя объект Selection, будьте осторожны: вы можете легко изменить выделенный пользователем фрагмент. Если вам нужно работать с некоей частью документа, но вы не хотите изменять этот фрагмент, используйте диапазон, абзац, предложение и т. д.

Применение свойства Type

Выделенные фрагменты могут быть разных типов, поэтому важно знать, что именно выделено (если вообще выделено). Например, если вы выполняете операцию над столбцом таблицы, то наверняка предпочтете убедиться, что выделен действительно столбец, и тем самым избежать генерации ошибки периода выполнения. Для этого проверяйте значение свойства Type объекта Selection. Свойство Type может содержать следующие значения перечислимого типа WdSelectionType:

  • wdSelectionBlock;
  • wdSelectionColumn;
  • wdSelectionFrame;
  • wdSelectionInlineShape;
  • wdSelectionIP;
  • wdSelectionNormal;
  • wdNoSelection;
  • wdSelectionRow;
  • wdSelectionShape.

Смысл большинства значений ясен из их имен, но для некоторых из них он не столь очевиден. Например, wdSelectionIP представляет курсор ввода. Значение wdInlineShape представляет изображение (image) или рисунок (picture), значение wdSelectionNormal - выделенный текст или комбинацию текста и других выделенных объектов.

В следующей процедуре код проверяет свойство Type объекта Selection, чтобы определить тип выделенного фрагмента. Для проверки введите какой-нибудь текст в документ, а затем запустите демонстрационную форму. После определения типа текущего выделенного фрагмента код больше ничего особенного не делает - просто использует конструкцию Case для сохранения полученного значения в строковой переменной и его последующего вывода в MessageBox:

' Visual Basic
Friend Sub ShowSelectionType()
 Dim str As String
 Select Case ThisApplication.Selection.Type
  Case Word.WdSelectionType.wdSelectionBlock
   str = "block"
  Case Word.WdSelectionType.wdSelectionColumn
   str = "column"
  Case Word.WdSelectionType.wdSelectionFrame
   str = "frame"
  Case Word.WdSelectionType.wdSelectionInlineShape
   str = "inline shape"
  Case Word.WdSelectionType.wdSelectionIP
   str = "insertion point"
  Case Word.WdSelectionType.wdSelectionNormal
   str = "normal text"
  Case Word.WdSelectionType.wdNoSelection
   str = "no selection"
  Case Word.WdSelectionType.wdSelectionRow
   str = "row"
  Case Else
   str = "(unknown)"
 End Select
 MessageBox.Show(str, "ShowSelectionType")
End Sub
 
// C#
public void ShowSelectionType() 
{
 string  str;
 switch (ThisApplication.Selection.Type) 
 {
  case Word.WdSelectionType.wdSelectionBlock:
   str = "block";
   break;
  case Word.WdSelectionType.wdSelectionColumn:
   str = "column";
   break;
  case Word.WdSelectionType.wdSelectionFrame:
   str = "frame";
   break;
  case Word.WdSelectionType.wdSelectionInlineShape:
   str = "inline shape";
   break;
  case Word.WdSelectionType.wdSelectionIP:
   str = "insertion point";
   break;
  case Word.WdSelectionType.wdSelectionNormal:
   str = "normal text";
   break;
  case Word.WdSelectionType.wdNoSelection:
   str = "no selection";
   break;
  case Word.WdSelectionType.wdSelectionRow:
   str = "row";
   break;
  default:
   str = "(unknown)";
   break;
 }
 MessageBox.Show(str, "ShowSelectionType");
}

Навигация и выделение текста

Кроме определения того, что именно было выделено, вы можете использовать ряд методов объекта Selection для навигации и выбора различных диапазонов текста в документе. Эти методы имитируют действия, выполняемые в результате нажатия клавиш на клавиатуре.

Методы HomeKey и EndKey

Применение этих методы изменяет размеры выделенного фрагмента.

HomeKey([Unit], [Extend]): действует так, будто вы нажали клавишу Home на клавиатуре.

EndKey([Unit], [Extend]): действует так, будто вы нажали клавишу End на клавиатуре.

Для аргумента Unit используется одно из значений перечислимого wdUnits.

  • WdLine Переход в начало или конец строки. Это значение по умолчанию.
  • WdStory Переход в начало или конец документа.
  • WdColumn Переход в начало или конец столбца. Допустимо только для таблиц.
  • WdRow Переход в начало или конец строки таблицы. Допустимо только для таблиц.
    В аргументе Extend указывается одно из значений перечислимого WdMovementType.
  • WdMove Перемещает выделенный фрагмент. При использовании с wdLine перемещает курсор ввода в начало или конец строки, а при использовании с wdStory - в начало или конец документа.
  • WdExtend Расширяет выделенный фрагмент. Конечный результат заключается в том, что новый объект Selection состоит из диапазона от курсора ввода до конечной позиции. Если начальная позиция не соответствует местонахождению курсора ввода, результат варьируется в зависимости от параметров, переданных методу. Например, если в данный момент выделена строка и метод HomeKey вызван с перечислимыми значениями wdStory и wdExtend, то строка не включается в новый выделенный фрагмент. Если метод EndKey вызван с перечислимыми значениями wdStory и wdExtend, строка включается в выделенный фрагмент. Такое поведение отражает действие комбинацией клавиш Ctrl+Shift+Home и Ctrl+Shift+End соответственно.
    Следующий код перемещает курсор ввода в начало документа вызовом метода HomeKey с wdStory и wdMove. Затем выделение расширяется до конца документа вызовом EndKey с wdExtend:
' Visual Basic
' Помещаем курсор ввода в начало документа
ThisApplication.Selection.HomeKey( _
  Word.WdUnits.wdStory, Word.WdMovementType.wdMove)
 
' Выделяем текст от курсора ввода до конца документа
ThisApplication.Selection.EndKey( _
  Word.WdUnits.wdStory, Word.WdMovementType.wdExtend)
 
// C#
// Помещаем курсор ввода в начало документа
Object unit = Word.WdUnits.wdStory;
Object extend = Word.WdMovementType.wdMove;
ThisApplication.Selection.HomeKey(ref unit, ref extend);
 
// Выделяем текст от курсора ввода до конца документа
unit = Word.WdUnits.wdStory;
extend = Word.WdMovementType.wdExtend;
ThisApplication.Selection.EndKey(ref unit, ref extend);

Методы, имитирующие действие клавиш со стрелками

Вы также можете изменять выделенный фрагмент вызовом методов, перечисленных ниже. Каждый из них принимает аргумент Count, который определяет, насколько единиц следует переместить выделение в данном направлении. Эти методы имитируют действие клавиш со стрелками.

  • MoveLeft([Unit], [Count], [Extend]).
  • MoveRight([Unit], [Count], [Extend]).
  • MoveUp([Unit], [Count], [Extend]).
  • MoveDown([Unit], [Count], [Extend]).

Аргумент Extend принимает те же два перечислимых значения - wdMove и wdExtend. Однако для методов MoveLeft и MoveRight в аргументе Unit передаются значения перечислимого типа WdUnits.

  • wdCharacter Перемещение в единицах символов. Это значение по умолчанию.
  • wdWord Перемещение в единицах слов.
  • wdCell Перемещение в единицах ячеек. Допустимо только для таблиц.
  • wdSentence Перемещение в единицах предложений.

Следующий фрагмент кода перемещает курсор ввода на три символа влево, а затем выделяет три слова справа от курсора ввода.

' Visual Basic
' Перемещаем курсор ввода влево на 3 символа
ThisApplication.Selection.MoveLeft( _
  Word.WdUnits.wdCharacter, 3, _
  Word.WdMovementType.wdMove)
 
' Выделяем 3 слова справа от курсора ввода
ThisApplication.Selection.MoveRight( _
  Word.WdUnits.wdWord, 3, _
  Word.WdMovementType.wdExtend)
 
// C#
// Перемещаем курсор ввода влево на 3 символа
Object unit = Word.WdUnits.wdCharacter;
Object count = 3;
Object extend = Word.WdMovementType.wdMove;
ThisApplication.Selection.MoveLeft(ref unit, ref count, 
 ref extend);
 
// Выделяем 3 слова справа от курсора ввода
unit = Word.WdUnits.wdWord;
count = 3;
extend = Word.WdMovementType.wdExtend;
ThisApplication.Selection.MoveRight(ref unit, ref count,
 ref extend);

Методы MoveUp и MoveDown принимают следующие значения перечислимого типа WdUnits.

  • wdLine Перемещение в единицах строк. Это значение по умолчанию.
  • wdParagraph Перемещение в единицах абзацев.
  • wdWindow Перемещение в единицах окна.
  • wdScreen Перемещение в единицах экрана.

Следующий фрагмент кода перемещает курсор ввода на одну строку вверх, а затем выделяет три абзаца подряд. Каким получится выделенный фрагмент, зависит от того, где находился курсор ввода и был ли выделен диапазон текста в начале данной операции.

' Visual Basic
' Перемещаем курсор ввода на одну строку вверх
ThisApplication.Selection.MoveUp( _
 Word.WdUnits.wdLine, 1, Word.WdMovementType.wdMove)
 
' Выделяем следующие 3 абзаца
ThisApplication.Selection.MoveDown( _
 Word.WdUnits.wdParagraph, 3, Word.WdMovementType.wdMove)
 
// C#
// Перемещаем курсор ввода на одну строку вверх
Object unit = Word.WdUnits.wdLine;
Object count = 1;
Object extend = Word.WdMovementType.wdMove;
ThisApplication.Selection.MoveUp(ref unit, ref count, ref extend);
 
// Выделяем следующие 3 абзаца
unit = Word.WdUnits.wdParagraph;
count = 3;
extend = Word.WdMovementType.wdMove;
ThisApplication.Selection.MoveDown(ref unit, ref count, 
  ref extend);

Метод Move

Метод Move свертывает указанный диапазон или выделенный фрагмент, а затем перемещает свернутый объект на заданное количество единиц. Следующий код свертывает исходный объект Selection и перемещает его на три слова вперед. В итоге курсор ввода оказывается в начале третьего слова:

' Visual Basic
ThisApplication.Selection.Move(Word.WdUnits.wdWord, 3)
 
// C#
Obiect unit = Word.WdUnits.wdWord;
Object count = 3;
ThisApplication.Selection.Move(ref unit, ref count);

Вставка текста

Самый простой способ вставить текст в документ - вызвать метод TypeText объекта Selection. Поведение TypeText зависит от режима вставки текста. В следующем коде объявляется объектная переменная для Selection и отключается режим замены текста (overtype option), если он включен. А если такой режим включен, перезаписывается любой текст, следующий за курсором ввода.

' Visual Basic
Friend Sub InsertTextAtSelection()
 Dim sln As Word.Selection = ThisApplication.Selection
 
 ' Проверяем, отключен ли режим замены
  ThisApplication.Options.Overtype = False
 
// C#
public void InsertTextAtSelection() 
{
 Word.Selection sln = ThisApplication.Selection;
 
 // Проверяем, отключен ли режим замены
  ThisApplication.Options.Overtype = false;

Далее код проверяет, не является ли текущий выделенный фрагмент курсором ввода. Если да, код вставляет предложение вызовом TypeText, а затем добавляет знак абзаца вызовом метода TypeParagraph:

' Visual Basic
With sln
 ' Проверяем, не состоит ли выделенный фрагмент только из курсора ввода
 If .Type = Word.WdSelectionType.wdSelectionIP Then
  .TypeText("Inserting at insertion point. ")
  .TypeParagraph()
 
// C#
// Проверяем, не состоит ли выделенный фрагмент только из курсора ввода
if (sln.Type == Word.WdSelectionType.wdSelectionIP ) 
{
 sln.TypeText("Inserting at insertion point. ");
 sln.TypeParagraph();
}

Код в блоке ElseIf/else if проверяет, является ли выделенный фрагмент обычным. Если да, во вложенном блоке If проверяется, установлен ли параметр ReplaceSelection. Если да, код использует метод Collapse объекта Selection для свертывания выделенного фрагмента до курсора ввода в начале выделенного блока текста. Затем вставляются текст и знак абзаца:

' Visual Basic
 ElseIf .Type = Word.WdSelectionType.wdSelectionNormal Then
  ' Переходим в начало выделенного фрагмента
   If ThisApplication.Options.ReplaceSelection Then
 .Collapse(Word.WdCollapseDirection.wdCollapseStart)
   End If
  .TypeText("Inserting before a text block. ")
  .TypeParagraph()
  Else
   ' Ничего не делаем
  End If
 End With
End Sub
 
// C#
 else if (sln.Type == Word.WdSelectionType.wdSelectionNormal ) 
 {
  // Переходим в начало выделенного фрагмента
  if ( ThisApplication.Options.ReplaceSelection ) 
  {
   Object direction = Word.WdCollapseDirection.wdCollapseStart;
   sln.Collapse(ref direction);
  }
  sln.TypeText("Inserting before a text block. ");
  sln.TypeParagraph();
 }
 else
 {
  // Ничего не делаем
 }
}

Если выделенный фрагмент не является курсором ввода или блоком текста, код просто ничего не делает.

Вы можете также использовать метод TypeBackspace объекта Selection, который имитирует функциональность клавиши Backspace. Однако объект Range дает гораздо больший контроль за вставкой текста и различными операциями над ним.

Объект Range

Объект Range представляет непрерывную область документа и создается определением позиций начального и конечного символов. Вы не ограничены одним объектом Range - в одном документе может быть несколько таких объектов. Если начальная и конечная позиции диапазона совпадают, вы получаете диапазон, который состоит только из курсора ввода. Но в принципе диапазон может охватывать хоть целый документ. Заметьте, что диапазон также включает все непечатаемые символы вроде пробелов, табуляторов и знаков абзацев.

Примечание Созданные вами диапазоны существуют до тех пор, пока выполняется ваш код.

У объекта Range много общих с объектом Selection членов. Основное различие между ними в том, что Selection всегда возвращает ссылку на фрагмент, выделенный в UI, а Range позволяет работать с текстом без визуального выделения в UI.

Основные преимущества применения объекта Range по сравнению с объектов Selection таковы:

  • обычно требует меньше кода для выполнения той или иной задачи;
  • не приводит к издержкам, связанным с перемещением или изменением выделенного фрагмента в активном документе;
  • обладает более широкими возможностями, чем Selection, в чем вы сами убедитесь в следующем разделе.

Определение и выделение диапазона

Вы можете определить диапазон в документе вызовом метода Range объекта Document с передачей начального и конечного значений. Следующий код создает новый объект Range, который включает первые семь символов в активном документе, в том числе непечатаемые знаки. Далее он обращается к методу Select объекта Range, чтобы выделить подсветкой полученный диапазон. Если вы опустите эту строку кода, объект Range будет невидим в пользовательском интерфейсе Word, но вы все равно сможете манипулировать им программным способом.

' Visual Basic
Dim rng As Word.Range = ThisDocument.Range(0, 7)
rng.Select()
 
// C#
Object start = 0;
Object end = 7;
Word.Range rng = ThisDocument.Range(ref start, ref end);
rng.Select();

Результаты показаны на рис. 9; в диапазон включены знак абзаца и пробел.

Рис. 9. Объект Range, который включает непечатаемые символы

Подсчет символов

Первый символ в документе имеет позицию 0, в ней же изначально находится курсор ввода. Позиция последнего символа равна общему числу символов в документе. Вы можете определить количество символов в документе через свойство Count набора Characters. Следующий код выделяет весь документ и выводит число символов в MessageBox:

' Visual Basic
Dim rng As Word.Range = _
  ThisDocument.Range(0, ThisDocument.Characters.Count)
' Или:
' rng = ThisDocument.Range()
rng.Select()
MessageBox.Show( _
  "Characters: " & ThisDocument.Characters.Count.ToString)
 
// C#
Object start = Type.Missing;
Object end = Type.Missing;
 
Word.Range rng = ThisDocument.Range(ref start, ref end);
rng.Select();
MessageBox.Show("Characters: " + 
 ThisDocument.Characters.Count.ToString());

Совет В Visual Basic .NET вызов метода Range без параметров возвращает диапазон, равный всему документу: если вы работаете со всем содержимым документа, указывать начальную и конечную позиции необязательно. Разработчиков на C# это, конечно, не касается, так как они должны передавать значения для любых необязательных параметров. В C# вы можете передать Type.Missing, чтобы присвоить необязательным параметрам значения по умолчанию.

Задание диапазонов

Если вас не волнует число символов и вам нужно выделить весь документ, используйте метод Select объекта Document через его свойство Range:

' Visual Basic
ThisDocument.Range.Select()
 
// C#
Object start = Type.Missing;
Object end = Type.Missing;
 
Word.Range rng = ThisDocument.Range(ref start, ref end);
rng.Select();

В ином случае с помощью свойства Content объекта Document определите диапазон, охватывающий основную область документа (document's main story), т. е. его содержимое без колонтитулов и других вспомогательных элементов:

' Visual Basic
Dim rng As Word.Range = ThisDocument.Content
rng.Select()
 
// C#
Word.Range rng = ThisDocument.Content;

Кроме того, для определения диапазона можно использовать методы и свойства других объектов. Например, чтобы выделить второе предложение в активном документе, в следующей процедуре выполняются такие операции:

  • создается переменная типа Range;
  • проверяется, есть ли в документе хотя бы два предложения;
  • аргументу Start метода Range присваивается позиция начала второго предложения;
  • аргументу End того же метода присваивается позиция конца второго предложения;
  • выделяется диапазон.
' Visual Basic
Friend Sub SelectSentence()
 Dim rng As Word.Range
 With ThisDocument
  If .Sentences.Count >= 2 Then
   ' Передаем значения Start и End для Range
   rng = .Range( _
 CType(.Sentences(2).Start, System.Object), _
 CType(.Sentences(2).End, System.Object))
   ' Выделяем полученный диапазон
   rng.Select()
  End If
 End With
End Sub
 
//C#
public void SelectSentence() 
{
  Word.Range rng;
 
 if (ThisDocument.Sentences.Count >= 2 ) 
 {
  // Передаем значения Start и End для Range
  Object start = ThisDocument.Sentences[2].Start;
  Object end = ThisDocument.Sentences[2].End;
  rng = ThisDocument.Range(ref start, ref end);
  rng.Select();
 }
}

Примечание Параметры, передаваемые свойству Range, объявляются с типом System.Object, так что код должен явным образом приводить типы их значений. Если вы работаете в Visual Basic .NET с параметром Option Strict, установленным в Off, это требование необязательно. А если вы работаете в C#, вы должны передавать параметры по ссылке.

Совет В отличие от набора Documents, который требует от разработчиков на C# применения скрытого метода get_Item для получения индивидуальных элементов, Paragraphs, Sentences и другие свойства возвращают массивы. Следовательно, разработчики на C# могут обращаться к этим массивам по индексам - так же, как и к любым другим массивам.

Если вам нужно лишь выделить второе предложение и больше ничего, код можно сократить, определив диапазон как объект Sentence. Тогда следующий код эквивалентен предыдущему:

' Visual Basic
Dim rng As Word.Range = ThisDocument.Sentences(2)
rng.Select()
 
// C#
Word.Range rng = ThisDocument.Sentences[2];
rng.Select();

Расширение диапазона

Определив объект Range, вы можете расширить его текущий диапазон методами MoveStart и MoveEnd. Оба метода принимают два одинаковых аргумента: Unit and Count. Аргумент Unit принимает одно из значений перечислимого типа WdUnits:

  • wdCharacter;
  • wdWord;
  • wdSentence;
  • wdParagraph;
  • wdSection;
  • wdStory;
  • wdCell;
  • wdColumn;
  • wdRow;
  • wdTable.

Аргумент Count указывает число единиц, на которое надо переместить начало или конец диапазона. В следующем примере определяется диапазон, состоящий из первых семи символов в документе. Затем код вызывает метод MoveStart объекта Range для смещения начальной точки диапазона на семь символов. После этого получаете диапазон, состоящий лишь из курсора ввода. Далее код сдвигает конечную позицию диапазона на семь символов вызовом MoveEnd.

' Visual Basic
' Определяем диапазон из 7 символов
Dim rng As Word.Range = _
  ThisDocument.Range(0, 7)
 
' Смещаем начальную позицию на 7 символов
rng.MoveStart(Word.WdUnits.wdCharacter, 7)
 
' Смещаем конечную позицию на 7 символов
rng.MoveEnd(Word.WdUnits.wdCharacter, 7)
 
// C#
// Определяем диапазон из 7 символов
Object start = 0;
Object end = 7;
Word.Range rng = ThisDocument.Range(ref start, ref end);
 
// Смещаем начальную позицию на 7 символов
Object unit = Word.WdUnits.wdCharacter;
Object count = 7;
rng.MoveStart(ref unit, ref count);
 
// Смещаем конечную позицию на 7 символов
unit = Word.WdUnits.wdCharacter;
count = 7;
rng.MoveEnd(ref unit, ref count);

Операции, выполняемые этим кодом, иллюстрирует рис. 10; в верхней строке показан начальный диапазон, во второй - диапазон после вызова MoveStart (из-за которого он сворачивается в курсор ввода), а в третьей - символы, выделенные после вызова MoveEnd.

Рис. 10. Применение методов MoveStart и MoveEnd для изменения размера диапазона

Получение начального и конечного символов в диапазоне

Для этого используйте свойства Start и End объекта Range, как показано ниже:

' Visual Basic
MessageBox.Show(String.Format( _
  "Start: {0}, End: {1}", rng.Start, rng.End), _
  "Range Start and End")
 
// C#
MessageBox.Show(String.Format("Start: {0}, End: {1}", 
 rng.Start, rng.End), "Range Start and End");

Применение SetRange для переопределения диапазона

Для переопределения размеров диапазона можно использовать и SetRange. Следующий код устанавливает исходный диапазон, начиная с первых семи символов в документе. Затем вызывает SetRange и переопределяет диапазон так, чтобы он начинался со второго предложения, а заканчивался - пятым:

' Visual Basic
Dim rng As Word.Range
rng = ThisDocument.Range(0, 7)
' Переопределяем существующий диапазон
rng.SetRange( _
 ThisDocument.Sentences(2).Start, _
 ThisDocument.Sentences(5).End)
 
// C#
Word.Range rng;
Object start = 0;
Object end = 7;
rng = ThisDocument.Range(ref start, ref end);
 
// Переопределяем существующий диапазон
rng.SetRange(ThisDocument.Sentences[2].Start, 
 ThisDocument.Sentences[5].End);
rng.Select();

Форматирование текста

Объект Range можно использовать и для форматирования текста. При этом вы должны:

  • определить форматируемый диапазон;
  • применить параметры форматирования;
  • при необходимости выделить отформатированный диапазон подсветкой.

Так, в процедуре-примере выделяется первый абзац в документе и изменяется размер и имя шрифта, а также тип выравнивания. Затем диапазон выделяется и выводится MessageBox, чтобы сделать паузу перед выполнение следующего блока кода, который трижды вызывает метод Undo объекта Document. Далее применяется стиль Normal Indent и вновь выводится MessageBox для паузы. Наконец, еще раз вызывается метод Undo и выводится MessageBox.

' Visual Basic
Friend Sub FormatRangeAndUndo()
 ' Устанавливаем Range на первый абзац
 Dim rng As Word.Range = _
   ThisDocument.Paragraphs(1).Range
 
 ' Изменяем параметры форматирования
 With rng
  .Font.Size = 14
  .Font.Name = "Arial"
  .ParagraphFormat.Alignment = _
  Word.WdParagraphAlignment.wdAlignParagraphCenter
 End With
 rng.Select()
 MessageBox.Show("Formatted Range", "FormatRangeAndUndo")
 
 ' Отменяем три предыдущих операции
 ThisDocument.Undo(3)
 rng.Select()
 MessageBox.Show("Undo 3 actions", "FormatRangeAndUndo")
 
 ' Применяем стиль Normal Indent
 rng.Style = "Normal Indent"
 rng.Select()
 MessageBox.Show("Normal Indent style applied", 
   "FormatRangeAndUndo")
 
 ' Отменяем одну операцию
 ThisDocument.Undo()
 rng.Select()
 MessageBox.Show("Undo 1 action", "FormatRangeAndUndo")
End Sub
 
// C#
public void FormatRangeAndUndo() 
{
 // Устанавливаем Range на первый абзац
 Word.Range rng = ThisDocument.Paragraphs[1].Range;
 
 // Изменяем параметры форматирования
 rng.Font.Size = 14;
 rng.Font.Name = "Arial";
 rng.ParagraphFormat.Alignment =
 Word.WdParagraphAlignment.wdAlignParagraphCenter;
 rng.Select();
 MessageBox.Show("Formatted Range", "FormatRangeAndUndo");
 
 // Отменяем три предыдущих операции
 Object times = 3;
 ThisDocument.Undo(ref times);
 rng.Select();
 MessageBox.Show("Undo 3 actions", "FormatRangeAndUndo");
 
 // Применяем стиль Normal Indent
 Object style = "Normal Indent";
 rng.set_Style(ref style);
 rng.Select();
 MessageBox.Show("Normal Indent style applied", 
   "FormatRangeAndUndo");
 
 // Отменяем одну операцию
 times = 1;
 ThisDocument.Undo(ref times);
 rng.Select();
 MessageBox.Show("Undo 1 action", "FormatRangeAndUndo");
}

Совет Поскольку свойство Range.Style ожидает Variant, разработчики на C# для установки стиля должны вызывать скрытый метод set_Style класса Range. Чтобы применить стиль к диапазону, следует передать в метод set_Style имя стиля или объект Style по ссылке. В тех случаях, когда в VBA какое-то свойство для чтения и записи определено как Variant, разработчики на C# должны вызывать соответствующий скрытый метод-аксессор наподобие set_Style и get_Style. Разработчики на Visual Basic .NET могут напрямую устанавливать или получать значение такого свойства.

Вставка текста

Свойство Text объекта Range позволяет вставлять или заменять текст в документе. Следующий фрагмент кода задает диапазон, который представляет собой курсор ввода в начале документа, и вставляет текст " New Text " (обратите внимание на пробелы) в позицию курсора ввода. Затем код выделяет подсветкой диапазон, включающий вставленный текст. Результат выполнения этого кода показан на рис. 11.

' Visual Basic
Dim str As String = "New Text"
Dim rng As Word.Range = ThisDocument.Range(0, 0)
rng.Text = str
rng.Select()
 
// C#
string  str = " new Text ";
Object start = 0;
Object end = 0;
Word.Range rng = ThisDocument.Range(ref start, ref end);
rng.Text = str;
rng.Select();

Рис. 11. Вставка нового текста в позицию курсора ввода

Замена текста в диапазоне

Если ваш диапазон - выделенный фрагмент, а не курсор ввода, тогда существующий текст в диапазоне заменяется вставляемым. Следующий код создает объект Range, который состоит из первых 12 символов в документе и заменяет их новой строкой.

' Visual Basic
rng = ThisDocument.Range(0, 12)
rng.Text = str
rng.Select()
 
// C#
start = 0;
end = 12;
rng = ThisDocument.Range(ref start, ref end);
rng.Text = str;
rng.Select();

Рис. 12. Вставка нового текста поверх существующего

Свертывание диапазона или выделенного фрагмента

Если вы работаете с объектом Range или Selection, то, возможно, захотите изменить выделенный фрагмент перед курсором вводом, чтобы избежать перезаписи существующего текста. Оба объекта (Range и Selection) предоставляют метод Collapse, принимающий два значения перечислимого типа WdCollapseDirection.

  • WdCollapseStart Свертывает выделенный фрагмент к началу. Так делается по умолчанию, если вы не указываете какое-либо значение.
  • WdCollapseEnd Свертывает выделенный фрагмент к концу.

Следующий код создает объект Range, состоящий из первого абзаца в документе и передает перечислимое значение wdCollapseStart для свертывания диапазона. Затем код вставляет новый текст и выделяет диапазон подсветкой. Результат показан на рис. 13.

' Visual Basic
Dim str As String = " New Text "
Dim rng As Word.Range = _
  ThisDocument.Paragraphs(1).Range
rng.Collapse(Word.WdCollapseDirection.wdCollapseStart)
rng.Text = str
rng.Select()
 
// C#
string  str = " new Text ";
Word.Range rng = ThisDocument.Paragraphs[1].Range;
Object direction = Word.WdCollapseDirection.wdCollapseStart;
rng.Collapse(ref direction);
rng.Text = str;
rng.Select();

Рис. 13. Текст, вставляемый после свертывания диапазона абзаца, помещается в начало абзаца

Если вы указываете значение wdCollapseEnd, новый текст вставляется в начало следующего абзаца:

' Visual Basic
rng.Collapse(Word.WdCollapseDirection.wdCollapseEnd)
 
// C#
Object direction = Word.WdCollapseDirection.wdCollapseEnd;
rng.Collapse(ref direction);

Рис. 14. Если диапазон абзаца свертывается к концу, новый текст вставляется в следующий абзац

Возможно, вы ожидали, что новое предложение будет вставлено до знака абзаца, но это не так, поскольку исходный диапазон включает знак абзаца. В следующем разделе поясняется, как работать со знаками абзацев для корректной вставки текста.

Вставка текста с учетом знаков абзацев

Всякий раз, когда вы создаете объект Range на основе абзаца, в него включаются и все непечатаемые символы. Взгляните на процедуру, в которой объявляются две строковые переменные и извлекается содержимое первого и второго абзацев в активном документе:

' Visual Basic
Friend Sub ManipulateRangeText()
 ' Получаем содержимое первого и второго абзацев
 Dim str1 As String = ThisDocument.Paragraphs(1).Range.Text
 Dim str2 As String = ThisDocument.Paragraphs(2).Range.Text
 
// C#
public void ManipulateRangeText() 
{
 // Получаем содержимое первого и второго абзацев
 string  str1 = ThisDocument.Paragraphs[1].Range.Text;
 string  str2 = ThisDocument.Paragraphs[2].Range.Text;

Следующий код создает две объектные переменные Range для первого и второго абзацев, а затем, используя свойство Text, меняет местами текст. Далее код поочередно выделяет каждый диапазон, создавая паузы с помощью операторов MessageBox. На рис. 15 показан документ после обмена текста между абзацами, при этом rng1 выделен подсветкой.

' Visual Basic
 ' Обмениваем текст между абзацами
 Dim rng1 As Word.Range = _
   ThisDocument.Paragraphs(1).Range
 rng1.Text = str2
 
 Dim rng2 As Word.Range = _
   ThisDocument.Paragraphs(2).Range
 rng2.Text = str1
 
 ' Делаем паузы, чтобы были видны результаты
 rng1.Select()
 MessageBox.Show(rng1.Text, "ManipulateRangeText")
 rng2.Select()
 MessageBox.Show(rng2.Text, "ManipulateRangeText")
 
// C#
 // Обмениваем текст между абзацами
 Word.Range rng1 = ThisDocument.Paragraphs[1].Range;
 rng1.Text = str2;
 
 Word.Range rng2 = ThisDocument.Paragraphs[2].Range;
 rng2.Text = str1;
 
 // Делаем паузы, чтобы были видны результаты
 rng1.Select();
 MessageBox.Show(rng1.Text, "ManipulateRangeText");
 rng2.Select();
 MessageBox.Show(rng2.Text, "ManipulateRangeText");

Рис. 15. Абзацы поменялись местами

Следующий блок кода изменяет rng1, используя метод MoveEnd, чтобы исключить знак абзаца из этого диапазона. Потом код заменяет остальной текст в первом абзаце, присваивая свойству Text объекта Range новую строку:

' Visual Basic
 rng1.MoveEnd(Word.WdUnits.wdCharacter, -1)
 ' Записываем новый текст для абзаца 1
 rng1.Text = "New content for paragraph 1."
 
// C#
 Object unit = Word.WdUnits.wdCharacter;
 Object count = -1;
 rng1.MoveEnd(ref unit, ref count);
 // Записываем новый текст для абзаца 1
 rng1.Text = "new content for paragraph 1.";

Далее просто заменяется текст в rng2, включая знак абзаца:

' Visual Basic
 rng2.Text = "New content for paragraph 2."
 
// C#
 rng2.Text = "new content for paragraph 2.";

После этого rng1 выделяется подсветкой, и выполнение кода приостанавливается оператором MessageBox; то же самое делается и с rng2. Поскольку rng1 был переопределен для исключения знака абзаца, исходные параметры форматирования этого абзаца сохраняются. Предложение вставлено поверх знака абзаца в rng2, из-за чего он перестает быть абзацем. На рис. 16 показан выделенный rng2; теперь он объединен с абзацем, который раньше был третьим.

' Visual Basic
 ' Пауза для отображения результата
 rng1.Select()
 MessageBox.Show(rng1.Text, "ManipulateRangeText")
 rng2.Select()
 MessageBox.Show(rng2.Text, "ManipulateRangeText")
 
// C#
 // Пауза для отображения результата
 rng1.Select();
 MessageBox.Show(rng1.Text, "ManipulateRangeText");
 rng2.Select();
 MessageBox.Show(rng2.Text, "ManipulateRangeText");

Рис. 16. Новый текст, вставленный в rng2, убирает его знак абзаца

Поскольку исходное содержимое обоих диапазонов было сохранено в переменных типа String, восстановить исходное состояние документа несложно. Следующая строка кода модифицирует rng1, чтобы включить в него знак абзаца, используя метод MoveEnd для расширения диапазона на один символ:

' Visual Basic
  rng1.MoveEnd(Word.WdUnits.wdCharacter, 1)
 
// C#
  unit = Word.WdUnits.wdCharacter;
  count = 1;
  rng1.MoveEnd(ref unit, ref count);

Затем код удаляет весь rng2. Это восстанавливает исходную позицию третьего абзаца.

' Visual Basic
  rng2.Delete()
 
// C#
  // Заметьте, что в C# нужно указывать оба параметра -
  // вычисление длины диапазона возлагается на вас
  unit = Word.WdUnits.wdCharacter;
  count = rng2.Characters.Count;
  rng2.Delete(ref unit, ref count);

Теперь в rng1 восстанавливается текст исходного абзаца:

' Visual Basic
  rng1.Text = str1
 
// C#
  rng1.Text = str1;

Наконец, последний блок кода вызывает метод Range.InsertAfter для вставки содержимого исходного второго абзаца за rng1 и выделяет rng1 подсветкой.

Все три абзаца с выделенным rng1 показаны на рис. 17. Заметьте, что второй абзац теперь включен в диапазон rng1, который был расширен для охвата вставленного текста.

' Visual Basic
  rng1.InsertAfter(str2)
  rng1.Select()
End Sub
 
// C#
  rng1.InsertAfter(str2);
  rng1.Select();
}

Рис. 17. Метод InsertAfter расширяет объект Range, чтобы охватить вставленный текст

Объект Bookmark

Объект Bookmark аналогичен объектам Range и Selection в том смысле, что он представляет непрерывную область в документе, заданную начальной и конечной позициями. Закладки (bookmarks) используются, чтобы помечать какое-либо место в документе, или в качестве контейнера текста. Объект Bookmark может состоять хоть из одного курсора ввода, хоть из всего документа. Допускается определение нескольких закладок в одном документе. Считайте закладку именованной областью документа, которая сохраняется вместе с ним.

Создание закладки

Набор Bookmarks является членом объектов Document, Range и Selection. Следующая процедура показывает, как создавать закладки в документе и использовать их для вставки текста. Ее код выполняет операции, описанные ниже.

  • Объявляет одну переменную типа Range и две переменные типа Bookmark и устанавливает свойство ShowBookmarks в True. Последнее приводит к тому, что курсор ввода становится серым, а в Bookmark включается диапазон текста, который на экране заключается в серые скобки.
    ' Visual Basic
    Friend Sub CreateBookmarks()
     Dim rng As Word.Range
     Dim bookMk1 As Word.Bookmark
     Dim bookMk2 As Word.Bookmark
     
     ' Отображаем закладки
     ThisDocument.ActiveWindow.View.ShowBookmarks = True
    // C#
    public void CreateBookmarks() 
    {
     Word.Range rng;
     Word.Bookmark bookMk1;
     Word.Bookmark bookMk2;
     
     // Отображаем закладки
     ThisDocument.ActiveWindow.View.ShowBookmarks = true;
    
  • Определяет объект Range как курсор ввода в самом начале документа.
    ' Visual Basic
    rng = ThisDocument.Range(0, 0)
     
    // C#
    Object start = 0;
    Object end = 0;
    rng = ThisDocument.Range(ref start, ref end);
    
  • Добавляет закладку с именем bookMk1, состоящую из объекта Range, и выводит MessageBox, чтобы приостановить выполнение кода. В этот момент вы увидите закладку в виде серого курсора ввода слева от начала абзаца, как показано на рис. 18.
    ' Visual Basic
    bookMk1 = ThisDocument.Bookmarks.Add( _
     "bookMk1", DirectCast(rng, Word.Range))
     
    ' Отображаем закладку
    MessageBox.Show("bookMk1 Text: " & bookMk1.Range.Text, _
     "CreateBookmarks")
     
    // C#
    Object range = rng;
    bookMk1 = ThisDocument.Bookmarks.Add("bookMk1", ref range);
     
    // Отображаем закладку
    MessageBox.Show("bookMk1 Text: " + bookMk1.Range.Text,
     "CreateBookmarks");
    

    Рис. 18. Закладка, определенная как курсор ввода, показывается в виде серого I-образного контура

  • Вызывает метод InsertBefore объекта Range для вставки текста перед закладкой и приостанавливает код с помощью MessageBox. На рис. 19 изображена закладка и вставленный текст. Заметьте, что вставленный текст включается в закладку.
    ' Visual Basic
    rng.InsertBefore("**InsertBefore bookMk1**")
     
    ' Показываем код закладки
    MessageBox.Show("bookMk1 Text: " & bookMk1.Range.Text, _
     "CreateBookmarks")
     
    // C#
    rng.InsertBefore("**InsertBefore bookMk1**");
     
    // Показываем код закладки
    MessageBox.Show("bookMk1 Text: " + bookMk1.Range.Text, 
     "CreateBookmarks");
    

    Рис. 19. Вставленный текст включается в закладку

  • Использует метод InsertAfter объекта Range для вставки текста после закладки. Заметьте, что вставленный текст появляется сразу за текстом, который был вставлен перед закладкой (рис. 20).
    ' Visual Basic
    rng.InsertAfter("**InsertAfter bookMk1**")
    MessageBox.Show("bookMk1 Text: " & bookMk1.Range.Text, _
     "CreateBookmarks")
     
    // C#
    rng.InsertAfter("**InsertAfter bookMk1**");
    MessageBox.Show("bookMk1 Text: " + bookMk1.Range.Text, 
     "CreateBookmarks");
    

    Рис. 20. Вставка текста после закладки

  • Переустанавливает объект Range на второй абзац в документе и создает новый объект Bookmark с именем bookMk2 для второго абзаца. Когда код приостанавливается на MessageBox, второй абзац оказывается заключенным в скобки (рис. 21).
    ' Visual Basic
    rng = ThisDocument.Paragraphs(2).Range
     
    ' Создаем новую закладку на втором абзаце
    bookMk2 = ThisDocument.Bookmarks.Add( _
     "bookMk2", DirectCast(rng, Word.Range))
    MessageBox.Show("bookMk2 Text: " & bookMk2.Range.Text, _
     "bookMk2 set")
     
    // C#
    rng = ThisDocument.Paragraphs[2].Range;
     
    // Создаем новую закладку на втором абзаце
    range = rng;
    bookMk2 = ThisDocument.Bookmarks.Add("bookMk2", ref range);
    MessageBox.Show("bookMk2 Text: " + bookMk2.Range.Text,  
     "bookMk2 set");
    

    Рис. 21. Закладка, охватывающая диапазон текста, отмечается квадратными скобками

  • Использует InsertBefore для вставки текста перед закладкой. На рис. 22 видно, что вставленный текст теперь включен в закладку.
    ' Visual Basic
    rng.InsertBefore("**InsertBefore bookMk2**")
    MessageBox.Show("bookMk2 Text: " & bookMk2.Range.Text, _
      "InsertBefore bookMk2")
     
    // C#
    rng.InsertBefore("**InsertBefore bookMk2**");
    MessageBox.Show("bookMk2 Text: " + bookMk2.Range.Text, 
      "InsertBefore bookMk2");
    

    Рис. 22. Когда закладка - диапазон текста, метод InsertBefore добавляет его к закладке

  • Вызывает InsertAfter для вставки текста после закладки. Заметьте, что этот текст вставляется за пределами закладки и не включается в нее. На рис. 23 показан документ после выполнения метода Select объекта Bookmark.
    ' Visual Basic 
    rng.InsertAfter("**InsertAfter bookMk2**")
    MessageBox.Show("bookMk2 Text: " & bookMk2.Range.Text, _
      "InsertAfter bookMk2")
     
    bookMk2.Select()
    MessageBox.Show("bookMk2.Select()", "CreateBookmarks")
     
    // C#
    rng.InsertAfter("**InsertAfter bookMk2**");
    MessageBox.Show("bookMk2 Text: " + bookMk2.Range.Text, 
     "InsertAfter bookMk2");
     
    bookMk2.Select();
    MessageBox.Show("bookMk2.Select()", "CreateBookmarks");
    

    Рис. 23. Текст, вставленный после закладки, в нее не включается

Набор Bookmarks

Набор Bookmarks содержит все закладки в документе. Кроме того, закладки могут находиться в таких частях документа, как колонтитулы (верхние и нижние). Следующая процедура перебирает набор Bookmarks и отображает имя каждой закладки в документе и содержимое ее свойства Range.Text методом MessageBox.Show:

' Visual Basic
Friend Sub ListBookmarks()
 Dim sw As New StringWriter
 Dim bmrk As Word.Bookmark
 
 For Each bmrk In ThisDocument.Bookmarks
  sw.WriteLine("Name: {0}, Contents: {1}", _
 bmrk.Name, bmrk.Range.Text)
 Next
 MessageBox.Show(sw.ToString(), "Boomarks and Contents")
End Sub
 
// C#
public void ListBookmarks() 
{
 StringWriter  sw = new StringWriter();
 
 foreach (Word.Bookmark bmrk in ThisDocument.Bookmarks)
 {
  sw.WriteLine("Name: {0}, Contents: {1}", 
  bmrk.Name, bmrk.Range.Text);
 } 
 MessageBox.Show(sw.ToString(), "Bookmarks and Contents");
}

Изменение текста закладки

Для этого достаточно присвоить новое значение свойству Range.Text закладки. Однако это приводит к удалению самой закладки. Простого способа вставить текст в закладку, чтобы впоследствии получить его, нет. Один из вариантов решения этой задачи - заменять закладку вставленным текстом (тем самым удаляя ее), а потом воссоздавать закладку, включая в нее весь вставленный текст:

' Visual Basic
Friend Sub BookmarkText()
 ' Создаем закладку, охватывающую первый абзац
 With ThisDocument
   .Bookmarks.Add("bkMark", _
 .Paragraphs(1).Range)
 
   ' Создаем диапазон в объекте Bookmark
   Dim rng As Word.Range = _
 .Bookmarks("bkMark").Range
 
   ' Заменяем текст диапазона (это приводит к удалению закладки)
   rng.Text = "New Bookmark Text."
 
   ' Воссоздаем закладку
   .Bookmarks.Add( _
 "bkMark", DirectCast(rng, Word.Range))
 
   ' Показываем закладку
   .ActiveWindow.View.ShowBookmarks = True
   MessageBox.Show(.Bookmarks("bkMark").Range.Text, _
  "BookmarkReplaceText")
 End With
  End Sub
 
// C#
public void BookmarkText() 
{
 // Создаем закладку, охватывающую первый абзац
 Object range = ThisDocument.Paragraphs[1].Range;
 ThisDocument.Bookmarks.Add("bkMark", ref range);
 
 // Создаем диапазон в объекте Bookmark
 Object name = "bkMark";
 Word.Range rng = ThisDocument.Bookmarks.get_Item(ref name).Range;
 
 // Заменяем текст диапазона (это приводит к удалению закладки)
 rng.Text = "new Bookmark Text.";
 
 // Воссоздаем закладку
 range = rng;
 ThisDocument.Bookmarks.Add("bkMark", ref range);
 
 // Показываем закладку
 ThisDocument.ActiveWindow.View.ShowBookmarks = true;
 name = "bkMark";
 MessageBox.Show(ThisDocument.Bookmarks.
  get_Item(ref name).Range.Text, "BookmarkReplaceText");
}

Более простой способ обновить содержимое объекта Bookmark - переустановить его свойство Range после модификации текста. В следующей процедуре в аргументе BookmarkName передается имя объекта Bookmark, а в аргументе NewText - строка, заменяющая содержимое свойства Text. Здесь объявляется объект Range, который потом присваивается свойству Range объекта Bookmark. Модификация Range.Text приводит к изменению текста в закладке, которая после этого вновь добавляется в набор Bookmarks:

' Visual Basic
Friend Sub ReplaceBookmarkText( _
  ByVal BookmarkName As String, _
  ByVal NewText As String)
 If ThisDocument.Bookmarks.Exists(BookmarkName) Then
  Dim rng As Word.Range = _
 ThisDocument.Bookmarks(BookmarkName).Range
  rng.Text = NewText
  ThisDocument.Bookmarks.Add( _
 BookmarkName, DirectCast(rng, Word.Range))
 End If
End Sub
 
// C#
public void ReplaceBookmarkText(string  BookmarkName, 
 string  NewText) 
{
 if (ThisDocument.Bookmarks.Exists(BookmarkName)) 
 {
  Object name = BookmarkName;
  Word.Range rng = ThisDocument.Bookmarks.
   get_Item(ref name).Range;
  rng.Text = NewText;
  Object range = rng;
  ThisDocument.Bookmarks.Add(BookmarkName, ref range);
 }
}

Вы вызываете эту процедуру, передавая ей имя закладки и новый текст:

' Visual Basic
ReplacBookmarkText("FirstNameBookmark", "Joe")
 
// C#
ReplaceBookmarkText("FirstNameBookmark", "Joe");

Поиск и замена текста

Редактируя документ в UI, вы, наверное, часто пользуетесь командами Find и Replace из меню Edit. Появляющееся при этом диалоговое окно позволяет задавать критерии поиска нужного вам текста. Команда Replace является расширением команды Find, давая возможность заменять найденный текст.

Поскольку объект Find - член объектов Selection и Range, вы можете обращаться к нему через любой из этих двух объектов.

Поиск текста через объект Selection

Если вы используете для поиска текста объект Selection, любые указанные вами критерии поиска применяются только к выделенному в данный момент тексту. Однако, если Selection включает лишь курсор ввода, тогда поиск ведется по всему документу. Когда обнаруживается элемент, удовлетворяющий критериям поиска, он автоматически выделяется подсветкой и становится текущим выделенным фрагментом. Следующая процедура ищет строку "dolor" и, как только находит ее первое вхождение, выделяет соответствующее слово, а затем выводит оповещение.

' Visual Basic
Public Sub FindInSelection()
 ' Смещаем выделение в начало документа
 ThisApplication.Selection.HomeKey( _
  Word.WdUnits.wdStory, Word.WdMovementType.wdMove)
 
 Dim strFind As String = "dolor"
 Dim fnd As Word.Find = ThisApplication.Selection.Find
 fnd.ClearFormatting()
 fnd.Text = strFind
 If fnd.Execute() Then
  MessageBox.Show("Text found.")
 Else
  MessageBox.Show("Text not found.")
 End If
End Sub
 
// C#
public void FindInSelection() 
{
 // Смещаем выделение в начало документа
 Object unit = Word.WdUnits.wdStory;
 Object extend = Word.WdMovementType.wdMove;
 ThisApplication.Selection.HomeKey(ref unit, ref extend);
 
 Word.Find fnd = ThisApplication.Selection.Find;
 fnd.ClearFormatting();
 
 Object findText = "dolor";
 Object matchCase = Type.Missing;
 Object matchWholeWord = Type.Missing;
 Object matchWildcards = Type.Missing;
 Object matchSoundsLike = Type.Missing;
 Object matchAllWordForms = Type.Missing;
 Object forward = Type.Missing;
 Object wrap = Type.Missing;
 Object format = Type.Missing;
 Object replaceWith = Type.Missing;
 Object replace = Type.Missing;
 Object matchKashida = Type.Missing;
 Object matchDiacritics = Type.Missing;
 Object matchAlefHamza = Type.Missing;
 Object matchControl = Type.Missing;
 
 if (fnd.Execute(ref findText, ref matchCase, ref matchWholeWord, 
  ref matchWildcards, ref matchSoundsLike, ref matchAllWordForms, 
  ref forward, ref wrap, ref format, ref replaceWith, 
  ref replace, ref matchKashida, ref matchDiacritics, 
  ref matchAlefHamza, ref matchControl))
 {
  MessageBox.Show("Text found.", "FindInSelection");
 } 
 else 
 {
  MessageBox.Show("Text not found.", "FindInSelection");
 }
}

Совет Критерии поиска являются кумулятивными, т. е. каждый последующий критерий добавляется к предыдущим. В связи с этим рекомендуется перед каждой операцией поиска очищать параметры форматирования, оставшиеся после предудыщуих операций поиска, вызовом метода ClearFormatting.

Настройка параметров поиска

Настроить параметры поиска можно двумя способами: установкой индивидуальных свойств объекта Find или передачей аргументов в метод Execute. Следующая процедура иллюстрирует оба варианта. Первый блок окда задает свойства объекта Find, а второй - аргументы для метода Execute. Код в обоих блоках выполняет одну и ту же операцию поиска - отличается лишь синтаксис. Поскольку вы вряд ли станете использовать множества параметров, требуемых методом Execute, и поскольку вы можете задать многие их значения как свойства объекта Find, это дает хороший шанс разработчикам на C# создать методы-оболочки, скрывающие сложности вызова метода Find.Execute. Разработчикам на Visual Basic этого делать не нужно.

' Visual Basic
Public Sub CriteriaSpecify()
 ' Задаем критерии поиска через свойства объекта Find
 With ThisApplication.Selection.Find
  .ClearFormatting()
  .Forward = True
  .Wrap = Word.WdFindWrap.wdFindContinue
  .Text = "ipsum"
  .Execute()
 End With
 
 ' Задаем критерии поиска через аргументы метода Execute
 With ThisApplication.Selection.Find
  .ClearFormatting()
  .Execute(FindText:="dolor", _
 Forward:=True, Wrap:=Word.WdFindWrap.wdFindContinue)
 End With
End Sub
 
// C#
public void CriteriaSpecify() 
{
 // Задаем критерии поиска через свойства объекта Find
 Word.Find fnd = ThisApplication.Selection.Find;
 
 fnd.ClearFormatting();
 fnd.Forward = true;
 fnd.Wrap = Word.WdFindWrap.wdFindContinue;
 fnd.Text = "ipsum";
 
 ExecuteFind(fnd);
 
 // Задаем критерии поиска через аргументы метода Execute
 fnd = ThisApplication.Selection.Find;
 fnd.ClearFormatting();
 
 Object findText = "dolor";
 Object wrap = Word.WdFindWrap.wdFindContinue;
 Object forward = true;
 ExecuteFind(fnd, wrap, forward);
}
 
private Boolean ExecuteFind(Word.Find find)
{
 return ExecuteFind(find, Type.Missing, Type.Missing);
}
 
private Boolean ExecuteFind(
  Word.Find find, Object wrapFind, Object forwardFind)
{
 // Простая оболочка Find.Execute:
 Object findText = Type.Missing;
 Object matchCase = Type.Missing;
 Object matchWholeWord = Type.Missing;
 Object matchWildcards = Type.Missing;
 Object matchSoundsLike = Type.Missing;
 Object matchAllWordForms = Type.Missing;
 Object forward = forwardFind;
 Object wrap = wrapFind;
 Object format = Type.Missing;
 Object replaceWith = Type.Missing;
 Object replace = Type.Missing;
 Object matchKashida = Type.Missing;
 Object matchDiacritics = Type.Missing;
 Object matchAlefHamza = Type.Missing;
 Object matchControl = Type.Missing;
 
 return find.Execute(ref findText, ref matchCase, 
  ref matchWholeWord, ref matchWildcards, ref matchSoundsLike, 
  ref matchAllWordForms, ref forward, ref wrap, ref format, 
  ref replaceWith, ref replace, ref matchKashida, 
  ref matchDiacritics, ref matchAlefHamza, ref matchControl);
}

Поиск текста через объект Range

Поиск текста через объект Range позволяет выполнять эту операцию, ничего не показывая в UI. Метод Find возвращает булево значение, указывающее результаты поиска. Этот метод также переопределяет объект Range в соответствии с критериями поиска, если заданный текст найден. То есть, если метод Find обнаруживает совпадение, диапазон перемещается в позицию, где найдено совпадение.

Следующая процедура определяет объект Range состоящим из второго абзаца в документе. Затем она вызывает метод Find, сначала очищая любые параметры форматирования, и ищет строку "faucibus". Код показывает результаты поиска, используя метод MessageBox.Show, и выделяет Range, чтобы он стал видимым. Если поиск заканчивается неудачей, выделяется второй абзац, а если он завершается удачно, выделяется найденное совпадение. C#-версия этого примера использует метод-оболочку ExecuteFind, о которой уже говорилось ранее.

' Visual Basic
Public Sub FindInRange()
 ' Задаем второй абзац как диапазон поиска
 Dim rng As Word.Range = _
   ThisDocument.Paragraphs(2).Range
 Dim fnd As Word.Find = rng.Find
 
 ' Очищаем существующие параметры форматирования
 fnd.ClearFormatting()
 ' Выполняем поиск
 fnd.Text = "faucibus"
 If fnd.Execute() Then
  MessageBox.Show("Text found.", "FindInRange")
 Else
  MessageBox.Show("Text not found.", "FindInRange")
 End If
 
 ' Если поиск удачен, показывается слово "faucibus",
 ' в ином случае - второй абзац
  rng.Select()
End Sub
 
// C#
public void FindInRange() 
{
 // Задаем второй абзац как диапазон поиска
 Word.Range rng = ThisDocument.Paragraphs[2].Range;
 Word.Find fnd = rng.Find;
 
 // Очищаем существующие параметры форматирования
 fnd.ClearFormatting();
 
 // Выполняем поиск
 fnd.Text = "faucibus";
 if (ExecuteFind(fnd))
 {
  MessageBox.Show("Text found.", "FindInRange");
 } 
 else 
 {
  MessageBox.Show("Text not found.", "FindInRange");
 }
 
 // Если поиск удачен, показывается слово "faucibus",
 // в ином случае - второй абзац
 rng.Select();
}

Перебор найденных элементов

Объект Find предоставляет свойство Found, которое возвращает True всякий раз, когда обнаруживается искомый элемент. Вы можете воспользоваться этим в своем коде, как показано в процедуре-примере. Здесь код ищет все вхождения строки "lorem" в активном документе с помощью объекта Range и при этом выделяет каждое найденное совпадение цветным шрифтом с полужирным начертанием. Затем код проверяет в цикле свойство Found и увеличивает счетчик на 1 при каждом обнаружении искомой строки. Далее процедура сообщает число вхождений заданной строки через MessageBox. C#-версия этого кода использует уже обсуждавшийся метод-оболочку ExecuteFind.

' Visual Basic
Public Sub FindInLoopAndFormat()
 Dim intFound As Integer
 Dim rngDoc As Word.Range = ThisDocument.Range
 Dim fnd As Word.Find = rngDoc.Find
 
 ' Ищем все вхождения слова "lorem" и выделяем их полужирным
 fnd.ClearFormatting()
 fnd.Forward = True
 fnd.Text = "lorem"
 fnd.Execute()
 Do While fnd.Found
  ' Задаем новые толщину и цвет шрифта.
  ' Заметьте, что каждое вхождение переустанавливает
  ' диапазон на найденный текст.
  rngDoc.Font.Color = Word.WdColor.wdColorRed
  rngDoc.Font.Bold = 600
  intFound += 1
  fnd.Execute()
 Loop
 MessageBox.Show( _
   String.Format("lorem found {0} times.", intFound), _
   "FindInLoopAndFormat")
End Sub
 
// C#
public void FindInLoopAndFormat() 
{
 int intFound = 0;
 
 Object start = 0;
 Object end = ThisDocument.Characters.Count;
 Word.Range rngDoc = ThisDocument.Range(ref start, ref end);
 Word.Find fnd = rngDoc.Find;
 
 // Ищем все вхождения слова "lorem" и выделяем их полужирным
 fnd.ClearFormatting();
 fnd.Forward = true;
 fnd.Text = "lorem";
 ExecuteFind(fnd);
 while (fnd.Found)
 {
  // Задаем новые толщину и цвет шрифта.
  // Заметьте, что каждое вхождение переустанавливает
  // диапазон на найденный текст.
  rngDoc.Font.Color = Word.WdColor.wdColorRed;
  rngDoc.Font.Bold = 600;
  intFound++;
  ExecuteFind(fnd);
 }
 MessageBox.Show(
  String.Format("lorem found {0} times.", intFound), 
  "FindInLoopAndFormat");
}

Совет Вам может показаться весьма странным, что диапазон rngDoc сначала ссылается на весь документ, а под конец - только на каждое вхождение, обнаруженное в рамках текущей операции поиска. Так и задумано: когда вы вызываете метод Find объекта Range, Word всегда обновляет этот объект, чтобы он ссылался на найденный текст. Если вам нужно сохранить ссылку на исходный диапазон, создайте вторую переменную, в которой будет храниться ссылка на исходную информацию. Если исходным диапазоном был весь документ (как в данном случае), необходимости во второй переменной нет, так как вы можете легко вновь получить ссылку на этот документ.

Замена текста

Есть несколько программных способов поиска и замены текста. В типичном варианте используется объект Find для перебора всего документа в поисках нужного текста, параметров форматирования или стиля. Если вы хотите заменять любой из найденных элементов, задействуйте свойство Replacement объекта Find. Оба объекта - Find и Replacement - предоставляют метод ClearFormatting. При выполнении операции поиска и замены вы должны вызывать методы ClearFormatting обоих объектов. Иначе можно закончить заменой текста с непредсказуемыми параметрами форматирования.

Для замены каждого найденного элемента применяйте метод Execute. Он принимает перечислимое WdReplace, в котором определено три значения.

  • wdReplaceAll Замена всех найденных элементов.
  • wdReplaceNone Ни один найденный элемент не заменяется.
  • wdReplaceOne Замена только первого найденного элемента.

Следующая процедра ищет и заменяет все вхождения строки "Lorum" на "Forum" в выделенном фрагменте. C#-версия этой процедуры использует вспомогательный метод ExecuteReplace, построенный по аналогии с уже обсуждавшимся методом-оболочкой ExecuteFind:

' Visual Basic
Friend Sub SearchAndReplace()
 With ThisApplication.Selection.Find
  .ClearFormatting()
  .Text = "Lorem"
  With .Replacement
   .ClearFormatting()
   .Text = "Forum"
  End With
  .Execute(Replace:=Word.WdReplace.wdReplaceAll)
 End With
End Sub
 
// C#
public void SearchAndReplace() 
{
 // Смещаем выделение к началу документа
 Object unit = Word.WdUnits.wdStory;
 Object extend = Word.WdMovementType.wdMove;
 ThisApplication.Selection.HomeKey(ref unit, ref extend);
 
 Word.Find fnd = ThisApplication.Selection.Find;
 fnd.ClearFormatting();
 fnd.Text = "Lorem";
 fnd.Replacement.ClearFormatting();
 fnd.Replacement.Text = "Forum";
 ExecuteReplace(fnd);
}
 
private Boolean ExecuteReplace(Word.Find find)
{
 return ExecuteReplace(find, Word.WdReplace.wdReplaceAll);
}
 
private Boolean ExecuteReplace(Word.Find find, 
 Object replaceOption)
{
 // Простая оболочка Find.Execute:
 Object findText = Type.Missing;
 Object matchCase = Type.Missing;
 Object matchWholeWord = Type.Missing;
 Object matchWildcards = Type.Missing;
 Object matchSoundsLike = Type.Missing;
 Object matchAllWordForms = Type.Missing;
 Object forward = Type.Missing;
 Object wrap = Type.Missing;
 Object format = Type.Missing;
 Object replaceWith = Type.Missing;
 Object replace = replaceOption;
 Object matchKashida = Type.Missing;
 Object matchDiacritics = Type.Missing;
 Object matchAlefHamza = Type.Missing;
 Object matchControl = Type.Missing;
  
 return find.Execute(ref findText, ref matchCase, 
  ref matchWholeWord, ref matchWildcards, ref matchSoundsLike, 
  ref matchAllWordForms, ref forward, ref wrap, ref format, 
  ref replaceWith, ref replace, ref matchKashida, 
  ref matchDiacritics, ref matchAlefHamza, ref matchControl);
}

Восстановление исходного выделения после поиска

Если вы ищете и заменяете текст в документе, то, наверное, захотите восстанавливать исходное выделение по окончании поиска. Следующая процедура использует два объекта Range: один - для сохранения текущего Selection, а другой - для задания всего документа в качестве диапазона поиска. Затем выполняется операция поиска и замены, после которой исходное выделение восстанавливается. C#-версия этой процедуры использует уже рассмотренный метод-оболочку ExecuteReplace:

' Visual Basic
Friend Sub ReplaceAndRestoreSelection()
  ' Сохраняем исходное выделение
 Dim rngStart As Word.Range = _
   ThisApplication.Selection.Range
 
 ' Задаем в качестве диапазона поиска весь документ
 Dim rngSearch As Word.Range = ThisDocument.Range
 
 With rngSearch.Find
  .ClearFormatting()
  .Text = "vel"
  With .Replacement
   .ClearFormatting()
   .Text = "VELLO"
  End With
  .Execute(Replace:=Word.WdReplace.wdReplaceAll)
 End With
 
 ' Восстанавливаем исходное выделение
 rngStart.Select()
End Sub
 
// C#
public void ReplaceAndRestoreSelection() 
{
 // Сохраняем исходное выделение
 Word.Range rngStart = ThisApplication.Selection.Range;
 
 // Задаем в качестве диапазона поиска весь документ
 Object start = 0;
 Object end = ThisDocument.Characters.Count;
 Word.Range rngSearch = ThisDocument.Range(ref start, ref end);
 
 Word.Find fnd = rngSearch.Find;
 fnd.ClearFormatting();
 fnd.Text = "vel";
 fnd.Replacement.ClearFormatting();
 fnd.Replacement.Text = "VELLO";
 ExecuteReplace(fnd);
 
 // Восстанавливаем исходное выделение
 rngStart.Select();
}

Печать

В Word встроена богатая функциональность для поддержки печати. С ее помощью очень легко распечатывать целые документы или их части.

Использование функции Print Preview

Вы можете вывести документ в режиме Print Preview (просмотра перед печатью), установив свойство PrintPreview документа в True:

' Visual Basic
ThisDocument.PrintPreview = True
 
// C#
ThisDocument.PrintPreview = true;

Для текущего документа с той же целью можно переключать значение свойства PrintPreview объекта Application. Если документ уже находится в режиме Print Preview, он будет показан в обычном режиме, а если он отображается в обычном режиме, то будет переключен в режим Print Preview:

' Visual Basic
Friend Sub TogglePrintPreview()
 ThisApplication.PrintPreview = Not ThisApplication.PrintPreview
End Sub
 
// C#
public void TogglePrintPreview() 
{
 ThisApplication.PrintPreview = !ThisApplication.PrintPreview;
}

Метод PrintOut

С помощью этого метода вы посылаете документ или его часть на принтер. Метод можно вызывать из объекта Application или Document. Следующий фрагмент кода печатает активный документ с параметрами по умолчанию:

' Visual Basic
ThisDocument.PrintOut()
 
// C#
Object background = Type.Missing;
Object append = Type.Missing;
Object range = Type.Missing;
Object outputFileName = Type.Missing;
Object from = Type.Missing;
Object to = Type.Missing;
Object item = Type.Missing;
Object copies = Type.Missing;
Object pages = Type.Missing;
Object pageType = Type.Missing;
Object printToFile = Type.Missing;
Object collate = Type.Missing;
Object fileName = Type.Missing;
Object activePrinterMacGX = Type.Missing;
Object manualDuplexPrint = Type.Missing;
Object printZoomColumn = Type.Missing;
Object printZoomRow = Type.Missing;
Object printZoomPaperWidth = Type.Missing;
Object printZoomPaperHeight = Type.Missing;
 
ThisDocument.PrintOut(ref background, ref append,
 ref range, ref outputFileName, ref from, ref to, 
 ref item, ref copies, ref pages, ref pageType, 
 ref printToFile, ref collate, ref activePrinterMacGX, 
 ref manualDuplexPrint, ref printZoomColumn, ref printZoomRow, 
 ref printZoomPaperWidth, ref printZoomPaperHeight);

Метод PrintOut принимает множество необязательных аргументов, позволяющих тонко настраивать процесс печати документа (табл. 2).

Табл. 2. Часто используемые аргументы PrintOut

 

Аргумент Описание
Background Установите в True, чтобы продолжить работу с Word, пока печатается документ
Append Используется с аргументом OutputFileName. Если он равен True, указанное имя документа добавляется к имени файла, заданному в аргументе OutputFileName. А если он равен False, указанное имя документа заменяет значение, заданное в OutputFileName
Range Диапазон страницы. Может быть любым значением из перечислимого типа WdPrintOutRange: wdPrintAllDocument, wdPrintCurrentPage, wdPrintFromTo, wdPrintRangeOfPages или wdPrintSelection
OutputFileName Если PrintToFile равен True, этот аргумент задает путь и имя выходного файла
From Номер начальной страницы, когда Range равен wdPrintFromTo
To Номер конечной, когда Range равен wdPrintFromTo
Item Печатаемый элемент. Может быть любым значением из перечислимого типа WdPrintOutItem: wdPrintAutoTextEntries, wdPrintComments, wdPrintDocumentContent, wdPrintKeyAssignments, wdPrintProperties или wdPrintStyles
Copies Число печатаемых копий
Pages Номера и диапазоны печатаемых страниц; разделяются запятыми. Например, "2, 6-10" приводит к печати страницы 2 и страниц 6-10
PageType Тип печатаемых страниц. Может быть любым значением WdPrintOutPages: wdPrintAllPages, wdPrintEvenPagesOnly или wdPrintOddPagesOnly
PrintToFile Если равен True, инструкции печати посылаются не на принтер, а в файл. Не забудьте указать имя файла в OutputFileName
Collate Используется при печати множества копий документа. Если равен True, копии печаются последовательно: сначала первая копия, потом - вторая и т. д.
FileName Доступен только при работе с объектом Application. Путь и имя файла печатаемого документа. Если этот аргумент опущен, Word печатает активный документ.
ManualDuplexPrint Установите в True, чтобы печатать документ на обеих сторонах листов на принтере, где такая возможность не реализована на аппаратном уровне

Следующая процедура печатает первую страницу активного документа:

' Visual Basic
Friend Sub PrintOutDoc()
 ThisDocument.PrintOut( _
   Background:=True, _
   Append:=False, _
   Range:=Word.WdPrintOutRange.wdPrintCurrentPage, _
   Item:=Word.WdPrintOutItem.wdPrintDocumentContent, _
   Copies:=2, _
   Pages:=1, _
   PageType:=Word.WdPrintOutPages.wdPrintAllPages, _
   PrintToFile:=False, _
   Collate:=True, _
   ManualDuplexPrint:=False)
End Sub
 
// C#
public void PrintOutDoc() 
{
 Object background = true;
 Object append = false;
 Object range = Word.WdPrintOutRange.wdPrintCurrentPage;
 Object outputFileName = Type.Missing;
 Object from = Type.Missing;
 Object to = Type.Missing;
 Object item = Word.WdPrintOutItem.wdPrintDocumentContent;
 Object copies = 2;
 Object pages = 1;
 Object pageType = Word.WdPrintOutPages.wdPrintAllPages;
 Object printToFile = false;
 Object collate = Type.Missing;
 Object fileName = Type.Missing;
 Object activePrinterMacGX = Type.Missing;
 Object manualDuplexPrint = Type.Missing;
 Object printZoomColumn = Type.Missing;
 Object printZoomRow = Type.Missing;
 Object printZoomPaperWidth = Type.Missing;
 Object printZoomPaperHeight = Type.Missing;
  
 ThisDocument.PrintOut(ref background, ref append,
  ref range, ref outputFileName, ref from, ref to, 
  ref item, ref copies, ref pages, ref pageType, 
  ref printToFile, ref collate, ref activePrinterMacGX, 
  ref manualDuplexPrint, ref printZoomColumn, ref printZoomRow, 
  ref printZoomPaperWidth, ref printZoomPaperHeight);
}

Создание таблиц в Word

Набор Tables является членом объектов Document, Selection и Range, а это значит, что вы можете создавать таблицы в любом из этих контекстов. Для добавления таблицы к заданному диапазону используйте метод Add. Следующий код добавляет таблицу из трех строк и четырех столбцов в начало активного документа:

' Visual Basic
Dim rng as Word.Range = _
  ThisDocument.Range(0, 0)
ThisDocument.Tables.Add(rng, 3, 4)
 
// C#
Object start = 0;
Object end = 0;
Word.Range rng = ThisDocument.Range(ref start, ref end);
 
Object defaultTableBehavior = Type.Missing;
Object autoFitBehavior = Type.Missing;
ThisDocument.Tables.Add(rng, 3, 4, ref defaultTableBehavior,
 ref autoFitBehavior);

Работа с объектом Table

Создав таблицу, вы автоматически добавляете ее в набор Tables объекта Document, после чего можете ссылаться на нее по номеру:

' Visual Basic
Dim tbl As Word.Table = ThisDocument.Tables(1)
 
// C#
Word.Table tbl = ThisDocument.Tables[1];

У каждого объекта Table есть свойство Range, которое позволяет напрямую задавать атрибуты форматирования, и свойство Style для применения одного из встроенных стилей к таблице:

' Visual Basic
With ThisDocument.Tables(1)
 .Range.Font.Size = 8
 .Style = "Table Grid 8"
End With
 
// C#
Word.Table tbl = ThisDocument.Tables[1];
tbl.Range.Font.Size = 8;
Object style = "Table Grid 8";
tbl.set_Style(ref style);

Набор Cells

Каждый объект Table включает набор Cells, где индивидуальные объекты Cell представляют ячейки таблицы. Вы ссылаетесь на ячейку по ее местоположению в таблице. Следующий код ссылается на ячейку, расположенную на пересечении первой строки с первым столбцом, а затем добавляет в нее текст и форматирует ее:

' Visual Basic
With ThisDocument.Tables (1)
 With .Cell(1, 1).Range
  .Text = "Name"
  .ParagraphFormat.Alignment = _
   Word.WdParagraphAlignment.wdAlignParagraphRight
 End With
End With
 
// C#
Word.Range rng = ThisDocument.Tables[1].Cell(1, 1).Range;
rng.Text = "Name";
rng.ParagraphFormat.Alignment =
 Word.WdParagraphAlignment.wdAlignParagraphRight;

Строки и столбцы

Ячейки в таблице организованы в строки и столбцы. Чтобы добавить в таблицу новую строку, вызовите метод Add:

' Visual Basic
Dim tbl As Word.Table = ThisDocument.Tables(1)
tbl.Rows.Add()
 
// C#
Word.Table tbl = ThisDocument.Tables[1];
Object beforeRow = Type.Missing;
tbl.Rows.Add(ref beforeRow);

Хотя число столбцов обычно определяется при создании таблицы, столбцы можно добавлять методом Add и после ее создания. Следующий код вставляет в таблицу новый столбец перед первым существующим столбцом, а затем использует метод DistributeWidth, чтобы задать всем столбцам одинаковую ширину:

' Visual Basic
Dim tbl As Word.Table = ThisDocument.Tables(1)
tbl.Columns.Add(tbl.Columns(1))
tbl.Columns.DistributeWidth
 
// C#
Word.Table tbl = ThisDocument.Tables[1];
Object beforeColumn = tbl.Columns[1];
tbl.Columns.Add(ref beforeColumn);
tbl.Columns.DistributeWidth();

Связывая все воедино

В следующем примере таблица создается в конце активного документа и заполняется значениями свойств документа:

' Visual Basic
Public Sub CreateTable()
 ' Переходим в начало документа
 Dim rng As Word.Range = _
  ThisDocument.Range(0, 0)
 
 ' Вставляем какой-то текст и знаки абзацев
 rng.InsertBefore("Document Statistics")
 rng.Font.Name = "Verdana"
 rng.Font.Size = 16
 rng.InsertParagraphAfter()
 rng.InsertParagraphAfter()
 rng.SetRange(rng.End, rng.End)
 
 ' Добавляем таблицу
 Dim tbl As Word.Table = rng.Tables.Add( _
  ThisDocument.Paragraphs(2).Range, 3, 2)
 
 ' Форматируем таблицу и применяем стиль
 tbl.Range.Font.Size = 12
 tbl.Columns.DistributeWidth()
 tbl.Style = "Table Colorful 2"
 
 ' Вставляем текст в ячейки
 tbl.Cell(1, 1).Range.Text = "Document Property"
 tbl.Cell(1, 2).Range.Text = "Value"
 tbl.Cell(2, 1).Range.Text = "Number of Words"
 tbl.Cell(2, 2).Range.Text = ThisDocument.Words.Count.ToString
 tbl.Cell(3, 1).Range.Text = "Number of Characters"
 tbl.Cell(3, 2).Range.Text = _
   ThisDocument.Characters.Count.ToString
 tbl.Select()
End Sub
 
// C#
public void CreateTable() 
{
 // Переходим в начало документа
 Object start = 0;
 Object end = 0;
 Word.Range rng = ThisDocument.Range(ref start, ref end);
 
 // Вставляем какой-то текст и знаки абзацев
 rng.InsertBefore("Document Statistics");
 rng.Font.Name = "Verdana";
 rng.Font.Size = 16;
 rng.InsertParagraphAfter();
 rng.InsertParagraphAfter();
 rng.SetRange(rng.End, rng.End);
 
 // Добавляем таблицу
 Object defaultTableBehavior = Type.Missing;
 Object autoFitBehavior = Type.Missing;
 Word.Table tbl = rng.Tables.Add(
  ThisDocument.Paragraphs[2].Range, 3, 2, 
  ref defaultTableBehavior, ref autoFitBehavior);
 
 // Форматируем таблицу и применяем стиль
 tbl.Range.Font.Size = 12;
 tbl.Columns.DistributeWidth();
 Object style = "Table Colorful 2";
 tbl.set_Style(ref style);
 
 // Вставляем текст в ячейки
 tbl.Cell(1, 1).Range.Text = "Document Property";
 tbl.Cell(1, 2).Range.Text = "value";
 tbl.Cell(2, 1).Range.Text = "Number of Words";
 tbl.Cell(2, 2).Range.Text = 
  ThisDocument.Words.Count.ToString();
 tbl.Cell(3, 1).Range.Text = "Number of Characters";
 tbl.Cell(3, 2).Range.Text = 
  ThisDocument.Characters.Count.ToString();
 tbl.Select();
}

Резюме

Word предоставляет богатую объектную модель, которая позволяет программно контролировать Word и создание документов из управляемого кода. Эта статья даст вам лишь первое представление о доступных возможностях. Если у вас есть желание продолжить изучение объектной модели, читайте справочный файл по VBA в Word. Информации, полученной вами из этой статьи, вполне достаточно для решения любой задачи, связанной с созданием документов и их редактированием.


Может пригодится:


Автор: Mary Chipman, MCW Technologies, LLC
Прочитано: 33358
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (0)

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру