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

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

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

Объектная модель Excel с точки зрения разработчика под .NET
Рассматриваются некоторые объекты Microsoft Office Excel 2003 и объясняется, как их использовать при создании решений с помощью Microsoft Visual Studio Tools for Office. Основное внимание уделяется объектам Application, Workbook, Worksheet и Range. В примерах кода на Visual Basic .NET и Visual C# демонстрируются некоторые свойства, методы и события каждого объекта.

Аннотация

Рассматриваются некоторые объекты Microsoft Office Excel 2003 и объясняется, как их использовать при создании решений с помощью Microsoft Visual Studio Tools for Office. Основное внимание уделяется объектам Application, Workbook, Worksheet и Range. В примерах кода на Visual Basic .NET и Visual C# демонстрируются некоторые свойства, методы и события каждого объекта.
Скачайте ExcelObj.exe по ссылке Microsoft Download Center.

Содержание

Введение

Разработчикам, собирающимся использовать Microsoft® Visual Studio Tools for Office, и тем, кто просто хочет задействовать COM Automation для управления приложениями Microsoft Office Excel 2003, нужно знать, как обеспечить взаимодействие с объектами, предоставляемыми объектной моделью Excel. В Excel есть сотни объектов, и вам может понадобиться любой из них, но начинать знакомство с объектной моделью все же лучше с очень малого подмножества доступных объектов. К ним относятся:

  • Application;
  • Workbook;
  • Worksheet;
  • Range.

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

Совет Вообще говоря, разработчикам на Microsoft Visual Basic® .NET иметь дело с объектами Microsoft Office легче, чем разработчикам на Microsoft Visual C#® по одной важной причине: методы Visual Basic for Applications (VBA) часто содержат необязательные параметры, и Visual Basic .NET поддерживает такие параметры. Разработчики на C# столкнутся с необходимостью передавать значение для каждого необязательного параметра метода, а разработчики на Visual Basic .NET смогут использовать именованные параметры, чтобы передавать лишь нужные значения. Кроме того, C# не поддерживает свойства с параметрами (за исключением индексных свойств), а многие свойства объектов в Excel принимают параметры. Свойства вроде Application.Range легко доступны в VBA и Visual Basic .NET, но разработчикам на C# придется прибегнуть к отдельным методам-аксессорам (например вместо свойства Range применяется метод get_Range). Различия в программировании на Visual Basic .NET и C# показываются в этом документе по мере изложения материала.

Вы увидите, что объектная модель Excel по большей части прямо эмулирует его пользовательский интерфейс (UI). Не так сложно догадаться, что объект Application является оболочкой всего приложения, а каждый объект Workbook содержит набор объектов Worksheet. Также понятно, что объект Range является основным абстрактным представлением ячеек, позволяющим работать с отдельными ячейками или группами ячеек.

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

Совет В коде на Visual Basic .NET, представленном в этом документе, часто встречаются вызовы методов CType и DirectCast. Дело в том, что для проекта-примера включен параметр Option Strict, и Visual Basic .NET требует явного преобразования типов. Многие методы и свойства объектов Excel возвращают типы Object или полагаются на позднее связывание (late binding). Например, свойство Application.ActiveSheet возвращает Object, а не Worksheet, как можно было бы ожидать. Поэтому для строгого контроля типов в примере установлен параметр Option Strict и каждое преобразование типа выполняется явно. (В Visual Basic .NET без использования Option Strict можно написать код, который отлично компилируется, но терпит неудачу при выполнении. В этом и состоит смысл Option Strict - он значительно снижает вероятность того, что неправильное преобразование типа в период выполнения приведет к исключению.) Тот, кто программирует на C#, наверняка оценит это решение.

В документе приводятся ссылки на проект-пример ExcelObjectModel.sln. Он содержит рабочую книгу Excel и работающий с ней код на Visual Basic .NET. Не все примеры, приведенные здесь, входят в этот проект, но любой пример, состоящий более чем из одной-двух строк кода, включен в рабочую книгу, а в проекте задана гиперссылка для вызова соответствующего кода.

Совет Из-за ограниченного размера описать в этой статье каждый объект и все его члены просто нельзя. Нет возможности и детально рассмотреть какую-то часть классов. Лучшее средство исследования любой большой объектной модели - окно Object Browser, где для каждого класса можно найти список, в котором перечислены члены этого класса. Вы увидите, что немалая часть членов, рассмотренных в этом документе, присутствует сразу в нескольких разных классах: например, метод PrintOut, обсуждаемый в контексте набора Sheets, имеется у Chart, Worksheet, Range и других объектов. Цель документа - дать вам представление о доступных возможностях, а остальное зависит от вашей любознательности.

Объект Application

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

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

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

Члены, управляющие состоянием и отображением в Excel

Объект Application содержит большое количество свойств, управляющих общим состоянием Excel. В табл. 1 перечислено подмножество свойств объекта Application, относящихся к состоянию.

Табл 1. Некоторые свойства Application, управляющие состоянием Excel

 

Свойство Тип Описание
Cursor XlMousePointer (xlDefault, xlIBeam, xlNorthwestArrow, xlWait) Возвращает или устанавливает форму курсора мыши
EditDirectlyInCell Boolean Сообщает или задает, можно ли редактировать ячейки прямо по месту (в самих ячейках). При значении False можно редактировать ячейки только в строке формулы (formula bar)
FixedDecimal Boolean При значении True для определения количества десятичных разрядов во всех числовых значениях используется свойство FixedDecimalPlaces, в ином случае - свойство FixedDecimalPlaces игнорируется (значение по умолчанию - False)
FixedDecimalPlaces Long Задает количество десятичных разрядов, используемых в числовых значениях, если свойство FixedDecimal равно True
Interactive Boolean Сообщает или задает, может ли пользователь работать в Excel с помощью клавиатуры и мыши; если вы в обработчике исключения присваиваете этому свойству значение False, то в конце обработки обязательно присвойте True. Сам Excel не возвращает свойству первоначальное значение
MoveAfterReturn Boolean При значении True (по умолчанию), когда пользователь нажимает Enter, выделенной становится следующая ячейка
MoveAfterReturnDirection xlDirection (xlDown, xlToLeft, xlToRight, xlUp) Указывает направление, в котором перемещается выделение после нажатия Enter (если MoveAfterReturn равно True). Значение по умолчанию - xlDown
ScreenUpdating Boolean Если это свойство равно True, Excel обновляет свое окно после каждого вызова метода. Чтобы сэкономить время и придать приложению более профессиональный вид, можно отключить обновление на время выполнения вашего кода. После выполнения своего кода верните этому свойству значение True. Excel не восстанавливает это значение автоматически
SheetsInNewWorkbook Long Возвращает или устанавливает количество листов, автоматически помещаемых Excel в новые рабочие книги
StandardFont String Возвращает или устанавливает имя шрифта Excel по умолчанию; новое значение свойства начинает действовать только после перезапуска Excel
StandardFontSize Long Возвращает или устанавливает размер шрифта Excel по умолчанию; новое значение свойства начинает действовать только после перезапуска Excel
StartupPath (только для чтения) String Возвращает полный путь к папке, которая содержит надстройки (add-ins), выполняемые при запуске Excel
TemplatesPath (только для чтения) String Возвращает полный путь к папке, содержащей шаблоны; это значение задает одну из специальных папок Windows

Из всех свойств, перечисленных в табл. 1, вам скорее всего понадобится свойство ScreenUpdating. С его помощью можно не только придать приложению более профессиональный вид, но и добиться, чтобы оно выполнялось быстрее - обновление экрана после каждого изменения может привести к огромным издержкам (особенно при программном заполнении большого диапазона). Однако важно не забывать вновь присваивать ему значение True по завершении ваших операций, так как Excel не делает этого автоматически. Поэтому при использовании свойства ScreenUpdating вам придется всегда писать код, аналогичный следующему фрагменту, где за счет обработки .NET-исключений гарантируется возобновление обновления экрана:

' Visual Basic
Try
  ThisApplication.ScreenUpdating = False
  ' Выполняем операции, обновляющие экран
 
Finally
  ThisApplication.ScreenUpdating = True
End Try
 
// C#
try
{
  ThisApplication.ScreenUpdating = false;
  // Выполняем операции, обновляющие экран
}
 
finally
{  ThisApplication.ScreenUpdating = true;
}

Объект Application также поддерживает группу свойств, управляющих отображением в Excel. При изменении таких свойств меняется то, что пользователи видят на экране. В табл. 2 перечислено подмножество таких свойств.

Табл 2. Некоторые из свойств Application, управляющие отображением в Excel

 

Свойство Тип Описание
DisplayAlerts Boolean Если равно True (по умолчанию), то при выполнении кода Excel в случае необходимости показывает предупреждающие сообщения, например при удалении листа. Чтобы отключить предупреждения, присвойте False. Excel действует так, будто вы задали значение по умолчанию для каждого предупреждения
DisplayFormulaBar Boolean Если равно True (по умолчанию), Excel показывает стандартную строку формулы для редактирования ячеек; чтобы скрыть эту строку, присвойте False
DisplayFullScreen Boolean Если равно True (по умолчанию - False), Excel выполняется в полноэкранном режиме (который отличается от того, когда окно Excel просто развертывается на весь экран)

Совет Как и в случае свойства ScreenUpdating, важно возвращать свойству DisplayAlerts значение True. Иначе, поскольку Excel не делает этого автоматически, он не будет предлагать сохранять рабочие книги перед закрытием, и тогда данные могут быть потеряны по неосторожности.

Члены, возвращающие объекты

Многие свойства объекта Application возвращают другие объекты. Поскольку стандартный шаблон проекта Microsoft Office в Visual Studio® .NET содержит лишь объекты ThisApplication и ThisWorkbook, для обращения к другим объектам Excel обычно требуется использовать члены класса Application, возвращающие объекты. Эти члены позволяют получить ссылку на заданный дочерний объект по таким свойствам, как ActiveWindow, или по свойствам - наборам объектов, например по Charts. В табл. 3 перечислено подмножество свойств объекта Application, возвращающих объекты.

Табл. 3. Подмножество свойств объекта Application, возвращающих объекты

 

Свойство Тип Описание
ActiveCell Range Возвращает ссылку на текущую активную ячейку активного окна (расположенного поверх других). Если активного окна нет, генерирует ошибку
ActiveChart Chart Возвращает ссылку на текущую активную диаграмму. Встроенная диаграмма считается активной, если она выбрана или активирована
ActiveSheet Object Возвращает ссылку на активный лист активной рабочей книги
ActiveWindow Window Возвращает ссылку на активное окно (расположенное поверх других) или Nothing, если активных окон нет
Charts Sheets Возвращает набор объектов Sheet (предок объектов Chart и Worksheet), содержащий ссылки на каждую из диаграмм активной рабочей книги
Selection Object Возвращает объект, выбранный в приложении. Это может быть Range, Worksheet или любой другой объект. Кроме того, это свойство имеется у класса Window - тогда выделение обычно является объектом Range. Если в данный момент не выбран ни один объект, возвращает Nothing
Sheets Sheets Возвращает набор объектов Sheet, содержащий ссылки на каждый из листов активной рабочей книги
Workbooks Workbooks Возвращает набор объектов Workbook, содержащий ссылки на каждую открытую рабочую книгу

Чаще всего вы будете использовать свойство Workbooks класса Application. Оно позволяет перебирать открытые рабочие книги, открывать или создавать рабочие книги. Поведение этого свойства описывается в следующем разделе.

Набор Workbooks

Набор Workbooks позволяет работать со всеми открытыми рабочими книгами, создавать рабочую книгу и импортировать данные в новую рабочую книгу. Ниже перечислены некоторые основные применения набора Workbooks.

  • Создание рабочей книгиЭто делается с помощью кода следующего вида (методу Add можно также передать имя шаблона рабочей книги):
    ' Visual Basic
    Dim wb As Excel.Workbook = ThisApplication.Workbooks.Add()
     
    // C#
    
    Excel.Workbook wb = ThisApplication.Workbooks.Add(Type.Missing);
  • Закрытие всех открытых рабочих книгВ отличие от большинства наборов этот позволяет закрыть все члены сразу. Следующий вызов метода закрывает все открытые рабочие книги:
    ' Visual Basic
    ThisApplication.Workbooks.Close()
     
    // C#
    ThisApplication.Workbooks.Close();
    
  • Открытие существующей рабочей книгиДля этого вызывается метод Open набора Workbooks. В простейшей своей форме метод Open используется так, как показано ниже. У метода Open масса необязательных параметров, определяющих его поведение при определенных обстоятельствах, но обычно эти параметры не нужны:
    ' Visual Basic
    Dim wb As Excel.Workbook = _
      ThisApplication.Workbooks.Open("C:\YourPath\YourWorkbook.xls")
     
    // C#
    Excel.Workbook wb = ThisApplication.Workbooks.Open( 
      "C:\\YourPath\\Yourworkbook.xls", 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing);
    

    Совет Если вы - разработчик на C#, вам придется привыкнуть к обилию значений Type.Missing в вызовах методов. Поскольку объектную модель Excel писали в расчете на VBA, многие ее методы принимают необязательные параметры - иногда до 30. Используйте либо многочисленные экземпляры значения Type.Missing или указывайте для каждого параметра определенное значение по умолчанию.

  • Открытие текстового файла, базы данных или XML-файла как рабочей книгиДля этого предназначены методы OpenText, OpenDatabase или OpenXml. Они очень гибки, и даже простое их описание займет больше места, чем позволяет объем документа. На данный момент достаточно, что вы знаете об их существовании - если потребуется загрузить любой из этих видов данных в Excel, вы сами изучите эти методы. Следующий код загружает в рабочую книгу текстовый файл (в котором разделителями являются запятые), начиная с его третьей строки:
    ' Visual Basic
    Dim wb as Excel.Workbook = _
      ThisApplication.Workbooks.OpenText("C:\Test.txt", StartRow:=3, _
      DataType:=xlDelimited, Comma:=True)
     
    // C#
    Excel.Workbook wb = 
      ThisApplication.Workbooks.OpenText("C:\\Test.txt", 
      Type.Missing, 3, Excel.XlTextParsingType.xlDelimited, 
      Excel.XlTextQualifier.xlTextQualifierDoubleQuote, 
      Type.Missing, Type.Missing, Type.Missing, True, 
      Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing);
    
  • Обращение к отдельным рабочим книгамК элементам набора Workbooks можно обращаться по индексам (позициям в наборе) или по именам рабочих книг. Однако ссылаясь на рабочую книгу по имени, будьте аккуратны: пока файл не сохранен, нужно использовать имя, показываемое в заголовке, но не содержащее расширение .xls:
    ' Visual Basic
    Dim wb As Excel.Workbook = ThisApplication.Workbooks(1)
    ' До сохранения Book1:
    wb = ThisApplication.Workbooks("Book1")
    ' После сохранения Book1:
    wb = ThisApplication.Workbooks("Book1.xls")
     
    // C#
    Excel.Workbook wb = ThisApplication.Workbooks[1];
    // До сохранения Book1:
    wb = ThisApplication.Workbooks["Book1"];
    // После сохранения Book1:
    wb = ThisApplication.Workbooks["Book1.xls"];
    

    Совет На конкретную рабочую книгу можно ссылаться через индексное свойство по умолчанию, Item. Кроме Item, у набора Workbooks, как и у всех наборов в Microsoft Office, есть свойство Count, которое возвращает число элементов в наборе (в данном случае - объектов Workbook).

Члены, выполняющие операции

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

  • CalculateЗаново вычисляет все открытые рабочие книги, заданную рабочую книгу или заданный диапазон:
    ' Visual Basic
    ThisApplication.Calculate
    ' Или...
    ThisWorkbook.Calculate
    ' Или...
    ThisApplication.Range("SomeNamedRange").Calculate
     
    // C#
    ThisApplication.Calculate();
    // Или...
    ThisWorkbook.Calculate();
    // Или...
    ThisApplication.get_Range("A1", "B12").Calculate();
    

    Примечание Как видно из примера, объекты Range и Worksheet тоже поддерживают метод Calculate. Используйте методы объектов, чтобы ограничить диапазон повторного вычисления минимальным количеством ячеек, которые вам требуется вычислить заново. Механизм повторного вычисления Excel очень быстр, но, если вы ограничите число обрабатываемых ячеек, то оптимизируете эту операцию. Используйте Application.Calculate, только когда нужно выполнить повторное вычисление, отражающее все неучтенные изменения во всех открытых рабочих книгах.

    Совет Visual Basic .NET и C# не совсем одинаково работают с членами объектов Excel. Так, в VBA и Visual Basic .NET можно обращаться к свойству Range объектов, а в C# это свойство доступно только через метод get_Range. В данном документе вы увидите примеры этого и других членов-акссесоров.

  • CheckSpellingВозвращает значение типа Boolean, сообщающее, правильно ли написан передаваемый параметр. При необходимости можно указать имя нестандартного словаря и логическое значение, указывающее, игнорировать ли регистр букв. В следующем фрагменте проверяется правильность написания вводимого значения, и результат показывается на листе:
    ' Visual Basic
    Private Sub TestSpelling()
      Dim rng As Excel.Range = _
      ThisApplication.Range("CheckSpelling")
      Dim strOut As String
     
      If ThisApplication.CheckSpelling( _
      rng.Offset(0, 1).Value.ToString) Then
        strOut = "Spelled correctly"
      Else
        strOut = "Spelled incorrectly"
      End If
      rng.Offset(0, 2).Value = strOut
    End Sub
     
    // C#
    private void TestSpelling()
    {
      // Если при вызове get_Range указывается только именованный
      // диапазон, вторым параметром должен быть Type.Missing
      Excel.Range rng = ThisApplication.
      get_Range("CheckSpelling", Type.Missing);
     
      // Заметьте: в C# требуется считывать и присваивать значения
      // свойству Value2 объекта Range, а не свойству Value, так как
      // свойство Value содержит параметр и поэтому недоступно
      // в C#-коде
      rng.get_Offset(0, 2).Value2 = 
        (ThisApplication.CheckSpelling(
      rng.get_Offset(0, 1).Value2.ToString(), 
        Type.Missing, Type.Missing) 
      ? "Spelled correctly" 
      : "Spelled incorrectly");
    }
    

    Совет В предыдущем фрагменте используется метод Offset объекта Range; вы еще не сталкивались ни с тем, ни с другим. Эти метод и объект рассматриваются в разделе по объекту Range. Несложно разобраться, как использовать класс Range: объект Range - это просто ячейка или группа ячеек. В данном случае объект Range ссылается на именованный диапазон CheckSpelling. Свойство Offset возвращает объект Range, содержащий заданное количество строк и столбцов, считая от левого верхнего угла Range, и позволяет работать с ячейками, позиция которых задана относительно известного места.

  • EvaluateПреобразовывает Excel-имя в реально существующую ссылку или значение. Этот метод позволяет создать ссылку в виде строки, а потом при необходимости преобразовать ее в настоящую ссылку на объект или вычислить значение выражения. В следующем примере приводится код, позволяющий ввести в лист адрес ячейки и поместить текст в ячейку с этим адресом:
    ' Visual Basic
    Private Sub TestEvaluate()
      Dim rng As Excel.Range = _
      ThisApplication.Range("Evaluate")
     
      Try
        Dim rngNew As Excel.Range = _
        ThisApplication.Evaluate( _
        DirectCast(rng.Offset(0, 1).Value), Excel.Range)
        rngNew.Value = "Hello, World!"
      Catch ex As Exception
        MessageBox.Show(ex.Message, ThisApplication.Name)
      End Try
    End Sub
     
    // C#
    private void TestEvaluate()
    {
      Excel.Range rng = ThisApplication.
        get_Range("Evaluate", Type.Missing);
     
      try 
      {
        Excel.Range rngNew = 
        (Excel.Range) ThisApplication.Evaluate(
        rng.get_Offset(0, 1).Value2);
        rngNew.Value2 = "Hello, World!";
      } 
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message, ThisApplication.Name);
      }
    }
    
  • MailSystem, MailSession, MailLogoff, MailLogon, SendMailЭти члены позволяют войти в установленную на компьютере систему электронной почты, отправить текущую рабочую книгу как вложение и выйти из почтовой системы. Свойство MailSystem задает установленную на компьютере систему электронной почты, а свойство MailSession возвращает ссылку на текущий сеанс электронной почты (необходимости во входе нет, если есть активный сеанс). В следующем примере демонстрационная рабочая книга отправляется как вложение в простом электронном сообщении:
    ' Visual Basic
    Private Sub TestEmail()
      If ThisApplication.MailSystem = Excel.XlMailSystem.xlMAPI Then
        If ThisApplication.MailSession Is Nothing Then
        Dim frm As New SendMail
        If frm.ShowDialog = DialogResult.OK Then
          ThisApplication.MailLogon( _
          frm.EmailName, frm.EmailPassword, frm.DownloadNewMail)
        End If
        End If
        Dim strEmail As String = _
       ThisApplication.Range("SendMail").Offset(0, 1). _
       Value.ToString
        ThisWorkbook.SendMail(strEmail, "Sample Excel Email")
        ThisApplication.MailLogoff()
      Else
        MessageBox.Show( _
       "This demonstration works only if MAPI is installed.")
      End If
    End Sub
     
    // C#
    private void TestEmail()
    {
      if (ThisApplication.MailSystem == 
        Excel.XlMailSystem.xlMAPI ) 
      {
        if ( ThisApplication.MailSession == null ) 
        {
        SendMail frm = new SendMail();
        if (frm.ShowDialog() == DialogResult.OK )
        {
          ThisApplication.MailLogon(frm.EmailName, 
            frm.EmailPassword, frm.DownloadNewMail);
        }
        }
        string  strEmail = ThisApplication.
        get_Range("SendMail", Type.Missing).
        get_Offset(0, 1).Value2.ToString();
        ThisWorkbook.SendMail(strEmail, 
        "Sample Excel Email", Type.Missing);
        ThisApplication.MailLogoff();
      } 
      else 
      {
        MessageBox.Show("This demonstration works only if " + 
        "MAPI is installed.");
      }
    }
    

    Примечание У класса Workbook есть метод SendMail; это имеет смысл, поскольку наименьший объект, который можно отправить по электронной почте, - сама рабочая книга. Заметьте, что метод SendMail не поддерживает никаких средств вложения текста в отправляемое сообщение и не обеспечивает особой гибкости при адресации. Очевидно, что эти члены предназначены лишь для отправки рабочей книги по электронной почте. Если вам нужны более широкие возможности, используйте другие средства работы с электронной почтой. Кроме того, если вы не находитесь в онлайновом режиме или не подключились к своей системе электронной почты, предыдущий пример кода потерпит неудачу. Чтобы избежать этой ситуации, не пытайтесь отправлять почту, если свойство MailSession возвращает Nothing.

  • Quit Позволяет программно выйти из Excel. Если присвоить свойству DisplayAlerts значение False, Excel не предложит сохранить несохраненные данные. Кроме того, если присвоить свойству Saved объекта Workbook значение True, Excel не станет предлагать сохранение независимо от того, есть изменения или нет:
    ' Visual Basic
    ThisApplication.Quit
     
    // C#
    ThisApplication.Quit();
    
  • UndoОтменяет последнюю операцию, выполненную средствами UI. Этот метод не влияет на операции, выполненные программно, и может отменить лишь одну операцию. Он не отличается особо богатыми возможностями, но позволяет отменять последнее действие, предпринятое пользователем перед запуском вашего кода:
    ' Visual Basic
    ThisApplication.Undo
     
    // C#
    ThisApplication.Undo();
    

Члены, используемые при операциях с файлами

Объект Application содержит несколько членов, позволяющих взаимодействовать с файловой системой в контексте приложений Excel. В следующих разделах описываются некоторые члены, которые понадобятся вам с наибольшей вероятностью. (Примеры, описанные в этом документе, относятся к листу Application File Handling демонстрационной рабочей книги.)

Свойство DefaultFilePath

Это простое свойство возвращает или устанавливает путь, используемый Excel для загрузки или сохранения файлов:

' Visual Basic
' При открытии рабочей книги:
ThisApplication.Range("DefaultFilePath").Value = _
  ThisApplication.DefaultFilePath
 
' При сохранении свойства DefaultFilePath:
ThisApplication.DefaultFilePath = _
  ThisApplication.Range("DefaultFilePath"). _
  Value.ToString
 
// C#
// При открытии рабочей книги:
ThisApplication.get_Range("DefaultFilePath", Type.Missing).
  Value2 = ThisApplication.DefaultFilePath;
 
// При сохранении свойства DefaultFilePath:
ThisApplication.DefaultFilePath = 
  ThisApplication.get_Range("DefaultFilePath", Type.Missing).
  Value2.ToString();

Свойство DefaultSaveFormat

Это свойство возвращает или устанавливает используемый по умолчанию формат сохранения рабочих книг. Оно принимает много значений перечислимого типа XlFileFormat. В примере рабочей книги можно выбрать любое доступное значение (рис. 1). В следующем фрагменте кода показывается, как загрузить или сохранить значение свойства.

В примере столбец E листа содержит список имен всех возможных значений перечислимого XlFileFormat (в диапазоне XlFileFormat), а столбец F - соответствующие целые значения. На рис. 2 показано подмножество этих двух столбцов. Именованный диапазон DefaultSaveFormat (рис. 1) содержит ссылку на диапазон XlFileFormat и позволяет выбирать значение из списка. После того как вы выбрали значение и указали, что хотите его сохранить, код находит выбранную строку методом Range.Find, а затем с помощью метода Range.Offset возвращает смещение найденного значения. (Дополнительную информацию о методе Range.Find см. в разделе "Поиск в диапазонах" далее в этом документе.) Наконец, код заносит целое значение (преобразованное в соответствующий перечислимый тип) обратно в свойство DefaultSaveFormat.

Прочитать текущее значение DefaultSaveFormat легко. Следующий код преобразовывает значение в текст и показывает его в соответствующем объекте Range листа:

' Visual Basic
' При открытии рабочей книги перечислимое значение
' преобразуется в строку
ThisApplication.Range("DefaultSaveFormat").Value = _
  ThisApplication.DefaultSaveFormat.ToString
 
// C#
// При открытии рабочей книги перечислимое значение
// преобразуется в строку
ThisApplication.get_Range("DefaultSaveFormat", Type.Missing).
  Value2 = ThisApplication.DefaultSaveFormat.ToString();

Присвоить выбранное значение свойству чуть сложнее. Для этого нужно выполнить три операции.

  • Прочитать имя выбранного формата сохранения из диапазона DefaultSaveFormat листа:
    ' Visual Basic
    ' Получаем новый формат сохранения в виде строки
    Dim strSaveFormat As String = _
      ThisApplication.Range("DefaultSaveFormat"). _
      Value.ToString()
     
    // C#
    // Получаем новый формат сохранения в виде строки
    string strSaveFormat = ThisApplication.
      get_Range("DefaultSaveFormat", Type.Missing).
      Value2.ToString();
    
  • Найти соответствующее целое значение в столбце, расположенном на листе по соседству с диапазоном XlFileFormat. Для этого вызывается метод Find класса Range и через свойство Range.Offset считывается значение из столбца, находящегося справа:
    ' Visual Basic
    Dim intSaveFormat As Integer = _
      CType(ThisApplication.Range("XlFileFormat"). _
      Find(strSaveFormat).Offset(0, 1).Value, Integer)
     
    // C#
    Excel.Range rng = ThisApplication.
      get_Range("xlFileFormat", Type.Missing);
    Excel.Range rngFind = rng.Find(strSaveFormat, 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
      Excel.XlSearchDirection.xlNext, Type.Missing, Type.Missing, 
      Type.Missing);
    // В C# вместо свойства Offset используется метод get_Offset:
    int intSaveFormat = 
      Convert.ToInt32(rngFind.get_Offset(0, 1).Value2);
    
  • Присвоить целое значение свойству DefaultSaveFormat:
    ' Visual Basic
    ThisApplication.DefaultSaveFormat = _
      CType(intSaveFormat, Excel.XlFileFormat)
     
    // C#
    ThisApplication.DefaultSaveFormat = 
      Excel.XlFileFormat) intSaveFormat;
    

     

Рис. 1. Выбор формата файла из списка доступных типов

Рис. 2. Подмножество диапазона XlFileFormat на примере листа

Свойство RecentFiles

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

' Visual Basic
Private Sub ListRecentFiles()
  Dim i As Integer
  Dim rng As Excel.Range = DirectCast( _
  ThisApplication.Range("RecentFiles"). _
  Cells(1, 1), Excel.Range)
  For i = 1 To ThisApplication.RecentFiles.Count
    rng.Offset(i - 1, 0).Value = _
    ThisApplication.RecentFiles(i).Name
  Next
End Sub
 
// C#
private void ListRecentFiles()
{
  Excel.Range rng = (Excel.Range)ThisApplication.
    get_Range("RecentFiles", Type.Missing).Cells[1, 1];
 
  for (int i = 1; i <= ThisApplication.RecentFiles.Count; i++)
  {
    rng.get_Offset(i - 1, 0).Value2 = 
    ThisApplication.RecentFiles[i].Name;
  }
}

Свойство FileDialog

Свойство FileDialog возвращает объект FileDialog, у которого четыре области применения. Он позволяет:

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

С помощью этого диалогового окна (объекта FileDialog) можно задействовать все возможности работы с файлами, доступные в Microsoft Office. Свойство FileDialog требует выбрать конкретное применение диалогового окна, передав одно из значений перечислимого типа msoFileDialogType: msoFileDialogFilePicker, msoFileDialogFolderPicker, msoFileDialogOpen или msoFileDialogSaveAs. После этого вы можете работать с объектом FileDialog, возвращаемым свойством.

Объект FileDialog, как и многие другие, принадлежит пространству имен Microsoft.Office.Core. Чтобы не набирать полный путь для каждого объекта Office, в проекте-примере это пространство имен импортируется оператором Imports/using. В фрагментах кода, приводимых в документе, предполагается, что в файл добавлена соответствующая ссылка на пространство имен:

' Visual Basic 
Imports Office = Microsoft.Office.Core
 
// C#
using Office = Microsoft.Office.Core;

Метод Show объекта FileDialog показывает диалоговое окно и возвращает -1, если нажата кнопка OK, и 0, если нажата Cancel. Если вы указали значение msoFileDialogOpen или msoFileDialogSaveAs, то можете вызвать метод Execute класса, чтобы открыть или сохранить файлы. Свойство SelectedItems содержит набор строк, каждая из которых задает имя одного выбранного файла.

Например, следующий код из примера рабочей книги предлагает открыть новую рабочую книгу. В этом фрагменте разрешается выбор нескольких файлов, очищается список фильтров, добавляются два фильтра, а затем открывается диалоговое окно, показанное на рис. 3. Если вы выберете один или несколько файлов, вызывается метод Execute объекта FileDialog, открывающий эти файлы:

' Visual Basic
With ThisApplication.FileDialog( _
  Office.MsoFileDialogType.msoFileDialogOpen)
  .AllowMultiSelect = True
  .Filters.Clear
  .Filters.Add "Excel Files", "*.xls;*.xlw"
  .Filters.Add "All Files", "*.*"
  If .Show <> 0 Then
    .Execute
  End If
End With
 
// C#
dlg = ThisApplication.get_FileDialog(
  Office.MsoFileDialogType.msoFileDialogOpen);
dlg.Filters.Clear();
dlg.Filters.Add("Excel Files", "*.xls;*.xlw", Type.Missing);
dlg.Filters.Add("All Files", "*.*", Type.Missing);
if(dlg.Show() != 0)
  dlg.Execute();

Рис. 3. Вывод стандартного диалогового окна File Open через класс FileDialog

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

' Visual Basic
With ThisApplication.FileDialog( _
  Office.MsoFileDialogType.msoFileDialogFolderPicker)
  If .Show <> 0 Then
    ThisApplication.Range("FolderPickerResults"). _
    Value = .SelectedItems.Item(1)
  End If
End With
 
// C#
dlg = ThisApplication.get_FileDialog(
  Office.MsoFileDialogType.msoFileDialogFolderPicker);
if (dlg.Show() != 0)
{
  ThisApplication.get_Range("FolderPickerResults", Type.Missing).
    Value2 = dlg.SelectedItems.Item(1);
}

Примечание В объекте Application также имеются методы GetOpenFileName и GetSaveAsFileName, позволяющие выбрать имя открываемого файла. Их можно применять, но, как вы увидите, соответствующие элементы управления Microsoft .NET Framework OpenFileDialog и SaveFileDialog, дают больше возможностей и проще в использовании.

Другие полезные члены

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

Класс WorksheetFunction

У объекта Application имеется свойство WorksheetFunction, возвращающее экземпляр класса WorksheetFunction. У этого класса есть несколько общих/статических методов, каждый из которых служит оболочкой для функций электронных таблиц Excel. Каждый из этих методов предоставляет доступ к одному из многих операторов и методов расчетов по электронным таблицам Excel, к которым нельзя обратиться из VBA каким-то иным способом. Некоторые члены (например метод And) дублируются операторами и методами Visual Basic .NET и C#, поэтому вряд ли вы будете их использовать.

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

  • Математические функции вроде Acos, Acosh, Asin, Asinh, Cosh, Degrees, Ln, Log, Median, Max, Min, Mode, Radians и др.
  • Функции баз данных (domain functions), позволяющие выполнять вычисления по диапазонам, например DAverage, DCount, DCountA, DGet, DMax, DMin, DProduct, DSum и др.
  • Логические функции, например IsErr, IsError, IsLogical, IsNA, IsNonText, IsNumber, IsText.
  • Статистические функции вроде BetaDist, BinomDist, ChiTest, ChiInv, LogNormDist, NegBinomDist, Pearson, SumProduct, SumSq, TDist, TTest, Var, VarP и др.
  • Функции электронных таблиц (spreadsheet functions), которые вы вряд ли будете использовать в .NET Framework, скажем, And, Or, Choose и др.
  • Функции, связанные с тайским языком (thai-related functions) позволяют работать с тайскими числами, календарем и валютой (говорят, разработчики Excel обожали тайскую пищу и добавили эти функции, чтобы местному тайскому ресторану было удобнее составлять счета, но это непроверенная информация). Примеры - BahtText, IsThaiDigit, ThaiDayOfWeek, ThaiDigit, ThaiMonthOfYear, ThaiNumSound, ThaiNumString, ThaiStringLength, ThaiYear, RoundBahtDown и RoundBahtUp.

Использовать класс WorksheetFunction в проекте Visual Studio .NET несложно. Так как в шаблоне проекта доступен объект ThisApplication, можно просто обратиться к свойству WorksheetFunction этого объекта. Приложение-пример содержит лист Other Application Members (рис. 4), обращающийся к некоторым членам этого класса.

Примечание Класс WorksheetFunction и его члены - хороший пример тому, почему работать с объектами Excel из Visual Basic значительно проще, чем из C#. При вызове многих методов класса WorksheetFunction разработчикам на C# приходится передавать до 30 параметров, большинство из которых пустые. Конечно, это дело можно упростить, написав оболочки для разных групп методов (с одним обязательным параметром, с двумя и т. д.). В данном документе преследуются ознакомительные цели, поэтому в примерах вызываются сами методы, а не их оболочки. Поэтому код на C# выглядит весьма громоздко, это уж точно.

По щелчку ссылки Demonstrate WorksheetFunction выполняется следующий код (о методе Sort см. в разделе "Сортировка данных в диапазоне"):

' Visual Basic
Private Sub TestWorksheetFunction()
  Dim ws As Excel.Worksheet = _
  DirectCast(ThisWorkbook.ActiveSheet, Excel.Worksheet)
  Dim rng As Excel.Range = ws.Range("RandomNumbers")
  Dim rnd As New System.Random
 
  Dim i As Integer
  For i = 1 To 20
    ws.Cells(i, 2) = rnd.Next(100)
  Next i
  rng.Sort(rng, _
  Orientation:=Excel.XlSortOrientation.xlSortColumns)
 
  With ThisApplication.WorksheetFunction
    ws.Range("Min").Value = .Min(rng)
    ws.Range("Max").Value = .Max(rng)
    ws.Range("Median").Value = .Median(rng)
    ws.Range("Average").Value = .Average(rng)
    ws.Range("StDev").Value = .StDev(rng)
  End With
End Sub
 
// C#
private void TestWorksheetFunction() 
{
  Excel.Worksheet ws = (Excel.Worksheet) ThisWorkbook.ActiveSheet;
  Excel.Range rng = ws.get_Range("RandomNumbers", Type.Missing);
  System.Random rnd = new System.Random();
 
  for ( int i = 1 ; i <= 20; i++)
    ws.Cells[i, 2] = rnd.Next(100);
 
  rng.Sort(rng, Excel.XlSortOrder.xlAscending, 
    Type.Missing, Type.Missing, Excel.XlSortOrder.xlAscending, 
    Type.Missing, Excel.XlSortOrder.xlAscending, 
    Excel.XlYesNoGuess.xlNo, Type.Missing,Type.Missing, 
    Excel.XlSortOrientation.xlSortColumns, 
    Excel.XlSortMethod.xlPinYin, 
    Excel.XlSortDataOption.xlSortNormal, 
    Excel.XlSortDataOption.xlSortNormal, 
    Excel.XlSortDataOption.xlSortNormal);
 
  Excel.WorksheetFunction wsf = ThisApplication.WorksheetFunction;
  ws.get_Range("Min", Type.Missing).Value2 = wsf.Min(rng, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing);
  ws.get_Range("Max", Type.Missing).Value2 = wsf.Max(rng, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing);
  ws.get_Range("Median", Type.Missing).Value2 = wsf.Median(rng,
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing);
  ws.get_Range("Average", Type.Missing).Value2 = wsf.Average(rng, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing);
  ws.get_Range("StDev", Type.Missing).Value2 = wsf.StDev(rng, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing);
}

Рис. 4. На листе WorksheetFunction демонстрируются полезные методы класса WorksheetFunction

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

' Visual Basic
dblAverage = ThisApplication.WorksheetFunction.Average( _
 12, 14, 13, 19, 21)
 
// C#
// Обратите внимание на количество значений Type.Missing --
// метод принимает 30 параметров
dblAverage = ThisApplication.WorksheetFunction.Average(
  12, 14, 13, 19, 21, 
  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
  Type.Missing, Type.Missing, Type.Missing, Type.Missing,
  Type.Missing);

Класс Window и набор Windows

Как и можно было ожидать, объект Application позволяет управлять окнами приложения Excel, а свойство Windows объекта Application используется для того, чтобы открывать, закрывать и упорядочивать окна Excel.

Свойство Windows возвращает набор объектов Window, и вы можете вызвать метод Arrange, чтобы упорядочить все открытые (или только видимые) окна. Чтобы задать, как расположить окна, указывается одно из значений перечислимого XlArrangeStyle и при необходимости информация о том, упорядочиваются ли только видимые окна и как синхронизировать прокрутку окон. Например, чтобы расположить окна слева направо (tile) в рабочем пространстве Excel, используется код вида:

' Visual Basic
ThisApplication.Windows.Arrange( _
  Excel.XlArrangeStyle.xlArrangeStyleTiled)
 
// C#
ThisApplication.Windows.Arrange( 
  Excel.XlArrangeStyle.xlArrangeStyleTiled, 
  Type.Missing, Type.Missing, Type.Missing);

Для программного создания окна можно вызвать метод NewWindow рабочей книги:

' Visual Basic
ThisWorkbook.NewWindow()
 
// C#
ThisWorkbook.NewWindow();

Поскольку метод NewWindow возвращает объект Window, можно написать следующий код, который присваивает заголовок новому окну и затем активизирует его:

' Visual Basic
With ThisWorkbook.NewWindow()
  .Caption = "New Window"
  .Activate()
End With
 
// C#
Excel.Window wnd = ThisWorkbook.NewWindow();
wnd.Caption = "New Window";
wnd.Activate();

Класс Window содержит свойства и методы, управляющие видом и поведением соответствующего окна: цветами, заголовком, видимостью элементов окна и поведением при прокрутке. Для задания свойств окна можно использовать код вида:

' Visual Basic
With ThisApplication.Windows(3)
  .GridlineColor = ColorTranslator.ToOle(Color.Red)
  .Caption = "A New Window"
  .DisplayHeadings = False
  .DisplayFormulas = False
  .DisplayWorkbookTabs = False
  .SplitColumn = 1
End With
 
// C#
wnd = ThisApplication.Windows[3];
wnd.GridlineColor = ColorTranslator.ToOle(Color.Red);
wnd.Caption = "A New Window";
wnd.DisplayHeadings = false;
wnd.DisplayFormulas = false;
wnd.DisplayWorkbookTabs = false;
wnd.SplitColumn = 1;

Совет В VBA и .NET при работе с цветами используются аналогичные парадигмы: и там, и там цвет задается тремя младшими байтами 32-битного целого, которые соответствуют красной, зеленой и синей составляющим цвета. Но цвета все же обрабатываются по-разному. Методом System.Drawing.ColorTranslator.ToOle можно преобразовать .NET-цвет в OLE-цвет, с которым работает VBA.

По щелчку Work with Windows на листе Other Application Members запускается процедура-пример TestWindows, содержащая все фрагменты кода, которые показаны в этом разделе. По щелчку Reset Windows на том же листе запускается процедура, закрывающая все окна, кроме первого, а затем развертывающая это окно:

' Visual Basic
Private Sub ResetWindows()
  Dim i As Integer
  For i = ThisApplication.Windows.Count To 2 Step -1
    ThisApplication.Windows(i).Close()
  Next
  ThisApplication.Windows(1).WindowState = _
  Excel.XlWindowState.xlMaximized
End Sub
 
// C#
private void ResetWindows()
{
  for (int i = ThisApplication.Windows.Count; i >= 2; i--)
    ThisApplication.Windows[i].Close(
    false, Type.Missing, Type.Missing);
  ThisApplication.Windows[1].WindowState = 
    Excel.XlWindowState.xlMaximized;
}

Класс Name и набор Names

У объекта Application есть свойство Names, возвращающее набор объектов Name. Каждый объект Name соответствует именованному диапазону Excel. Ссылку на именованный диапазон можно получить разными способами, в частности через свойство Names объекта Workbook или объекта Worksheet.

Для создания именованного диапазона служит метод Add набора Names, показанный в следующем фрагменте. Метод Add принимает помимо двух обязательных параметров несколько необязательных:

' Visual Basic
Dim nm As Excel.Name
nm = ThisApplication.Names.Add( _
  "NewName", "='Other Application Members'!$A$6")
 
// C#
Excel.Name nm;
 
nm = ThisApplication.Names.Add(
  "NewName", @"='Other Application Members'!$A$6", 
  Type.Missing, Type.Missing, Type.Missing, 
  Type.Missing, Type.Missing, Type.Missing, 
  Type.Missing, Type.Missing, Type.Missing);

Указав имя и местонахождение (и другие необязательные параметры), можно программно обратиться к диапазону:

' Visual Basic 
ThisApplication.Range("NewName").Value = "Hello, World!"
 
// C#
ThisApplication.get_Range(
  "NewName", Type.Missing).Value2 = "Hello, World!";

Чтобы получить информацию об именованном диапазоне, используйте различные свойства класса Name. Ниже перечислено несколько наиболее часто используемых членов.

  • Name возвращает имя, присвоенное именованному диапазону.
  • RefersTo возвращает строку, содержащую адрес диапазона в стандартном формате ("=SheetName!$B$25").
  • RefersToR1C1 возвращает адрес диапазона в формате "R1C1" ("=SheetName!R25C2").
  • Value возвращает ссылку на именованный диапазон, которая рарешается в содержимое диапазона.

По щелчку ссылки Work with Names в примере вызывается код, заполняющий область таблицы информацией обо всех именованных диапазонах:

' Visual Basic
Dim nm As Excel.Name
Dim rng As Excel.Range = ThisApplication.Range("Names")
Dim i As Integer
 
For i = 0 To ThisApplication.Names.Count - 1
  nm = ThisApplication.Names.Item(i + 1)
  rng.Offset(i, 0).Value = nm.Name
  ' Без ведущего "'" эти ссылки вычисляются,
  ' а не показываются напрямую
  rng.Offset(i, 1).Value = "'" & nm.RefersTo.ToString
  rng.Offset(i, 2).Value = "'" & nm.RefersToR1C1.ToString
  rng.Offset(i, 3).Value = nm.Value
Next i
 
// C#
Excel.Range rng = ThisApplication.get_Range("Names", Type.Missing);
for ( int i = 0 ; i <= ThisApplication.Names.Count - 1; i++)
{
  nm = ThisApplication.Names.Item(i + 1, 
    Type.Missing, Type.Missing);
  rng.get_Offset(i, 0).Value2 = nm.Name;
  // Без ведущего "'" эти ссылки вычисляются,
  // а не показываются напрямую
  rng.get_Offset(i, 1).Value2 = "'" + nm.RefersTo.ToString();
  rng.get_Offset(i, 2).Value2 = "'" + nm.RefersToR1C1.ToString();
  rng.get_Offset(i, 3).Value2 = nm.Value;
}

События класса Application

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

СоветПараметры, передаваемые обработчикам событий приложения Office, отличаются от параметров, используемых во встроенных обработчиках .NET-событий. Как правило, обработчики .NET-событий принимают переменную Object, ссылающуюся на объект, который инициировал событие, и второй параметр, унаследованный от базового класса EventArgs и содержащий дополнительную информацию о событии. В приложениях Office нет столь строго определенного шаблона событий, поэтому каждый обработчик события принимает произвольное число параметров, заданных его разработчиком.

Поведение объекта листа

Объект Application предоставляет ряд событий, связанных с листами (диаграммами и рабочими листами). В следующем списке приводится информация о многих из этих событий.

  • SheetActivate генерируется при активизации листа. Excel передает обработчику события переменную типа Object, содержащую ссылку на активизируемый лист.

  • СоветВ Excel всякий раз, когда передается переменная Object, ссылающаяся на лист, перед использованием ее следует явно привести к правильному типу (Worksheet или Chart в зависимости от обстоятельств). Если вы отключите в Visual Basic .NET параметр Option Strict, то сможете применять позднее связывание. Но тогда при наборе исходного кода функция IntelliSense станет недоступной, и вводить код будет сложнее. Во всех примерах этого документа, работающих с элементами набора Sheets, результат явно приводится к требуемому конкретному типу - Worksheet или Chart.
  • SheetBeforeDoubleClick генерируется при двойном щелчке листа до того, как Excel предоставляет обработчик двойного щелчка по умолчанию. Excel передает обработчику переменную Object со ссылкой на лист, объект Range, содержащий ячейку, наиболее близкую к месту двойного щелчка, и значение типа Boolean (по умолчанию - False), позволяющее отменить обработку события по умолчанию. (У диаграмм этого события нет.)
    СоветВсе события, в имени которых есть слово "Before", позволяют отменить обработку события по умолчанию. Параметр, передаваемый обработчику события, обычно именуется Cancel, а его значение по умолчанию - False. Если присвоить этому параметру True, Excel не выполняет обработку события по умолчанию.
  • SheetBeforeRightClick генерируется при щелчке листа правой кнопкой мыши до того, как Excel предоставит соовтетствующий обработчик по умолчанию. Excel передает обработчику переменную типа Object со ссылкой на лист, объект Range, содержащий ячейку, наиболее близкую к месту щелчка правой кнопкой, и значение типа Boolean (по умолчанию - False), позволяющее отменить обработку события по умолчанию. (У диаграмм этого события нет.)
  • SheetCalculate генерируется при повторном вычислении листа. Excel передает обработчику события переменную Object, содержащую ссылку на повторно вычисляемый лист.
  • SheetChange генерируется при изменении ячеек листа либо пользователем, либо кодом. Excel передает обработчику события переменную Object, содержащую ссылку на лист, и переменную типа Range, которая ссылается на измененный диапазон.
  • SheetDeactivate генерируется при деактивизации листа (т. е. когда он теряет фокус). Обработчик этого события выполняется, только когда фокус переходит на другой лист той же рабочей книги. Excel передает обработчику переменную Object, содержащую ссылку на лист, который стал неактивным.
  • SheetFollowHyperlink генерируется, когда пользователь щелкает гиперссылку в рабочей книге. Excel передает обработчику переменную Object со ссылкой на лист, где находится гиперссылка, и объект Hyperlink, содержащий ссылку на гиперссылку, которую щелкнул пользователь. (В проекте-примере на основе этого события реализуется навигация по примеру.)
  • SheetSelectionChange генерируется, когда на рабочем листе изменяется выделение (у диаграмм этого события нет). Excel передает обработчику события переменную Object со ссылкой на лист, где выделение изменилось, и переменную Range, ссылающуюся на новое выделение. (Заметьте: Excel не передает информацию об исходном выделении, которые было до изменения.)

Примечание Каждое из событий, описанных в этом разделе, доступно и как событие класса Workbook. События объекта Application генерируются для любого листа, открытого в данный момент в Excel. События объекта Workbook возникают, только если они относятся к листу, принадлежащему этой рабочей книге. Кроме того, те же события есть у класса Worksheet. В этом случае в имени события нет слова "Sheet" (например FollowHyperlink вместо SheetFollowHyperlink и т. д.), а обработчикам событий не передается ссылка на лист - подразумевается, что это объект, принявший событие. В остальном события, их применение и параметры идентичны событиям, описанным выше.

Поведение окна

Объект Application (и соответственно объект Workbook) предоставляет ряд событий, связанных с поведением объектов Window. Эти события описаны в следующем списке.

  • WindowActivate генерируется при активизации окна. Excel передает обработчику объект Workbook, ссылающийся на рабочую книгу, которой принадлежит окно, и объект Window, ссылающийся на выбранное окно. Как и другие события активизации, это событие генерируется только при перемещении фокуса в Excel. Если вы переходите в другое приложение, а потом возвращаетесь в Excel, это событие не возникает.
  • WindowDeactivate генерируется при деактивизации окна. См. информацию об этом событии в описании события WindowActivate.

    WindowResize генерируется, когда изменяется размер любого окна рабочей книги. Excel передает обработчику объект Workbook, ссылающийся на рабочую книгу, которой принадлежит окно, и объект Window, ссылающийся на окно, размер которого изменился.

Примечание В событиях класса Workbook обработчики событий не принимают ссылку на Workbook - подразумевается, что это объект, инициировавший событие.

Управление рабочей книгой

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

  • NewWorkbook генерируется при создании рабочей книги. Excel передает обработчику события переменнную Workbook, ссылающуюся на новую рабочую книгу. (Это событие предоставляется только для класса Application.)
  • WorkbookActivate генерируется при активизации рабочей книги. Excel передает обработчику переменную Workbook, ссылающуюся на рабочую книгу, которая становится активной. (Как и в случае других событий активизации, это событие происходит только при переходе от одной рабочей книги к другой.)
  • WorkbookBeforeClose генерируется при закрытии открытой рабочей книги, непосредственно перед обработкой события, выполняемой по умолчанию. Excel передает обработчику события переменную Workbook, ссылающуюся на закрываемую рабочую книгу, и значение типа Boolean (по умолчанию - False), позволяющее отменить обработку события по умолчанию (т. е. оставить рабочую книгу открытой).
    ВниманиеЕсли просто присвоить параметру Cancel значение True, не учитывая никаких условий, то ни одна рабочая книга не закроется.
  • WorkbookBeforePrint генерируется, когда начинается печать рабочей книги, непосредственно перед обработкой события по умолчанию. Excel передает обработчику переменную Workbook, ссылающуюся на печатаемую рабочую книгу, и значение типа Boolean (по умолчанию - False), позволяющее отменить обработку события по умолчанию (т. е. отменить запрашиваемую печать).
  • WorkbookBeforeSave генерируется при сохранении рабочей книги, непосредственно перед обработкой события по умолчанию. Excel передает обработчику переменную Workbook, ссылающуюся на сохраняемую рабочую книгу, и значение типа Boolean (по умолчанию - False), позволяющее отменить обработку события по умолчанию (т. е. отменить сохранение).
  • WorkbookDeactivate генерируется при деактивизации рабочей книги. Excel передает обработчику переменную Workbook, ссылающуюся на рабочую книгу, которая становится неактивной. (Как и в случае других событий активизации, это событие происходит только при переходе от одной рабочей книги к другой.)
  • WorkbookNewSheet генерируется при добавлении листа в рабочую книгу. Excel передает обработчику переменную Workbook со ссылкой на рабочую книгу и переменную Object со ссылкой на новый лист.
  • WorkbookOpen генерируется при открытии рабочей книги. Excel передает обработчику переменную Workbook со ссылкой на открываемую рабочую книгу.

Примечание Класс Workbook предоставляет свой набор событий, очень похожих на события, которые вы только увидели. Все события, имена которых начинаются с "Workbook", присутствуют и в списке событий класса Workbook, но в их именах нет этого префикса (т. е. Activate вместо WorkbookActivate и т. д.). Обработчики событий класса Workbook не принимают переменную Workbook в качестве параметра; подразумевается, что это объект, инициировавший событие. Кроме того, у класса Workbook имеются и события, эквивалентные событиям объекта Application, но Workbook перехватывает их только для одной рабочей книги, а не для всех. Далее в этом документе о событиях больше ничего не говорится, так как вам скорее всего хватит тех, которые были описаны выше.

Класс Workbook

Легко догадаться, что класс Workbook представляет одну рабочую книгу Excel. В этом разделе вы ознакомитесь с некоторыми членами класса Workbook, в том числе с наиболее часто используемыми свойствами и методами.

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

Свойства класса Workbook

В классе Workbook огромное количество членов (около 90), но многие из них предназначены для ситуаций, которые и в голову не придут большинству разработчиков. Так, свойство AutoUpdateFrequency возвращает число минут между обновлениями общей рабочей книги. Свойство Date1904 возвращает True, если рабочая книга использует систему дат 1904 (схему сериализации дат на компьютерах Macintosh, в которой значению 1 соответствует 2 января 1904 года). Свойство PasswordEncryptionAlgorithm позволяет задать точный алгоритм шифрования паролей и т. д.

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

Далее перечисляются некоторые наиболее часто используемые свойства класса Workbook.

  • Name, FullName, Path (типа StringКаждое из , только для чтения). этих свойств возвращает свою версию имени рабочей книги. FullName возвращает полный путь, в том числе имя файла рабочей книги, Name - часть, содержащую имя, а Path - часть, содержащую путь. По щелчку ссылки Name Information в рабочей книге примера выполняется код, возвращающий информацию, показанную на рис. 5:
    ' Visual Basic
    ThisApplication.Range("WorkbookName").Value = _
      ThisWorkbook.Name
    ThisApplication.Range("WorkbookPath").Value = _
      ThisWorkbook.Path
    ThisApplication.Range("WorkbookFullName").Value = _
      ThisWorkbook.FullName
     
    // C#
    ThisApplication.get_Range("WorkbookName", Type.Missing).
      Value2 = ThisWorkbook.Name;
    ThisApplication.get_Range("WorkbookPath", Type.Missing).
      Value2 = ThisWorkbook.Path;
    ThisApplication.get_Range("WorkbookFullName", Type.Missing).
      Value2 = ThisWorkbook.FullName;
    

    Рис. 5. Применение свойств Workbook, возвращающих информацию об имени

  • Password (типа StringВозвращает или устанавливает ). пароль для рабочей книги. Если указан непустой пароль, свойство HasPassword рабочей книги возвращает True. Можно прочитать значение свойства Password, но оно всегда равно "********". По щелчку ссылки Set Password рабочей книги примера выполняется код, который задает или очищает пароль рабочей книги в зависимости от того, что вы указали: текст или пустую строку. В примере используются форма Password проекта, показывающая окно с текстовым полем, и свойство Password:
    ' Visual Basic
    Private Sub SetPassword()
      Dim frm As New Password
     
      If frm.ShowDialog = DialogResult.OK Then
        ThisWorkbook.Password = frm.Password
      End If
      frm.Dispose()
    End Sub
     
    // C#
    private void SetPassword()
    {
      Password frm = new Password();
     
      if (frm.ShowDialog() == DialogResult.OK)
        ThisWorkbook.Password = frm.Value;
      frm.Dispose();
    }
    
  • PrecisionAsDisplayed (типа BooleanЕсли оно равно ). True, Excel выполняет вычисления, используя столько десятичных знаков, сколько их показывается на экране. При значении False (по умолчанию) в вычисления вовлекаются все доступные десятичные знаки, даже если отображаются не все из них. На рис. 6 показана рабочая книга примера, в которой это свойство равно True. Каждое из значений в столбце C является копией значения в столбце B, но для столбца C задано числовое форматирование: показываются только две десятичных позиции. Заметьте, что, если свойство PrecisionAsDisplayed имеет значение True, суммы различны, так как значения отличаются из-за округления. Если щелкнуть ссылку PrecisionAsDisplayed = False, суммы станут одинаковыми. По щелчку этой ссылки вызывается процедура, в которую - в зависимости от того, какую ссылку вы щелкнули, - передается True или False:
    ' Visual Basic
    Private Sub TestPrecisionAsDisplayed( _
      ByVal IsPrecisionAsDisplayedOn As Boolean)
      ThisWorkbook.PrecisionAsDisplayed = IsPrecisionAsDisplayedOn
    End Sub
     
    // C#
    private void TestPrecisionAsDisplayed(
      bool IsPrecisionAsDisplayedOn)
    {
      ThisWorkbook.PrecisionAsDisplayed = 
        IsPrecisionAsDisplayedOn;
    }
    

    Рис. 6. Если свойство PrecisionAsDisplayed равно True, Excel при вычислениях использует только видимые десятичные позиции

  • ReadOnly (типа BooleanВозвращает , только для чтения). True, если рабочая книга открыта только для чтения. Иногда требуется, чтобы приложение выполняло определенные действия, если данные нельзя сохранить в рабочей книге.
  • Saved (типа BooleanВозвращает или устанавливает ). состояние сохранения (saved state) рабочей книги. Если пользователь внес изменения в структуру или содержимое рабочей книги, свойство Saved имеет значение True. При попытке закрытия рабочей книги или выхода из Excel открывается окно, предлагающее сохранить рабочую книгу (если только вы не присвоили свойству Application.DisplayAlerts значение False). Если свойству Saved программно присвоено False, то Excel будет считать, что ваша рабочая книга уже сохранена, и не станет предлагать сохранить ее еще раз.

Работа со свойствами документа

Как и другие приложения Office, Excel позволяет хранить свойства документа в рабочей книге. Помимо встроенных свойств, в Excel можно добавлять собственные, нестандартные свойства. При выборе File | Properties открывается диалоговое окно (рис. 7), где можно выбрать вкладку Custom для создания и изменения нестандартных свойств.

Рис. 7. Используйте это диалоговое окно для определения свойств документа

Для работы со встроенными свойствами используется свойство BuiltInDocumentProperties класса Workbook, а для работы с собственными - свойство CustomDocumentProperties. Каждое из этих свойств возвращает объект DocumentProperties, являющийся набором объектов DocumentProperty. С помощью свойства Item этого набора можно считывать отдельные свойства по имени или по индексу в наборе. Полный список имен свойств приводится в документации по Excel, но его легко получить самому: в примере рабочей книги имеется процедура, выполняемая по щелчку ссылки Document Properties (рис. 8). Она вызывает метод DumpPropertyCollection для перечисления всех свойств и их текущих значений, затем выполняет ту же операцию для нестандартных свойств. Кроме того, процедура изменяет свойство Revision Number и создает нестандартное свойство:

' Visual Basic
Private Sub DisplayDocumentProperties()
  Dim prp As Office.DocumentProperty
  Dim prps As Office.DocumentProperties
 
  Dim rng As Excel.Range = _
  ThisApplication.Range("DocumentProperties")
  Dim i As Integer
 
  Try
    ThisApplication.ScreenUpdating = False
 
    Try
    prps = DirectCast( _
      ThisWorkbook.BuiltinDocumentProperties, _
      Office.DocumentProperties)
 
    ' Задаем свойство Revision Number
    prp = prps.Item("Revision Number")
    prp.Value = CType(prp.Value, Integer) + 1
 
    ' Получаем содержимое набора
    DumpPropertyCollection(prps, rng, i)
 
    Catch ex As Exception
    MessageBox.Show(ex.Message)
    End Try
 
    ' Работаем с нестандартными свойствами
    Try
    prps = DirectCast( _
      ThisWorkbook.CustomDocumentProperties, _
     Office.DocumentProperties)
    DumpPropertyCollection(prps, rng, i)
    Catch ex As Exception
    MessageBox.Show(ex.Message)
    End Try
 
    ' Добавляем нестандартное свойство
    Try
    ' Удаляем свойство, если оно существует
    prp = prps.Item("Project Name")
    prp.Delete()
    Catch
    ' При генерации исключения ничего не делаем
    End Try
 
    Try
    ' Добавляем новое свойство
    prp = prps.Add("Project Name", False, _
     Office.MsoDocProperties.msoPropertyTypeString, _
      "White Papers")
    Catch ex As Exception
    MessageBox.Show(ex.Message)
    End Try
  Finally
    ThisApplication.ScreenUpdating = True
  End Try
End Sub
 
Private Sub DumpPropertyCollection( _
  ByVal prps As Office.DocumentProperties, _
  ByVal rng As Excel.Range, ByRef i As Integer)
  Dim prp As Office.DocumentProperty
 
  For Each prp In prps
    rng.Offset(i, 0).Value = prp.Name
    Try
    If Not prp.Value Is Nothing Then
      rng.Offset(i, 1).Value = _
       prp.Value.ToString
    End If
    Catch
    ' Вообще ничего не делаем
    End Try
    i += 1
  Next
End Sub
 
// C#
private void DisplayDocumentProperties()
{
  Office.DocumentProperty prp = null;
  Office.DocumentProperties prps = 
    (Office.DocumentProperties) 
    ThisWorkbook.BuiltinDocumentProperties;
 
  Excel.Range rng = ThisApplication.
    get_Range("DocumentProperties", Type.Missing);
  int i = 0;
 
  try 
  {
    ThisApplication.ScreenUpdating = false;
 
    try 
    {
    // Задаем свойство Revision Number
    prp = prps["Revision Number"];
  prp.Value = Convert.ToInt32(prp.Value) + 1;
 
    // Получаем содержимое набора
    i = DumpPropertyCollection(prps, rng, i);
    } 
    catch (Exception ex) 
    {
    MessageBox.Show(ex.Message, ThisApplication.Name);
    }
 
    // Работаем с нестандартными свойствами
    try 
    {
  prps = (Office.DocumentProperties)
    ThisWorkbook.CustomDocumentProperties;
    DumpPropertyCollection(prps, rng, i);
    } 
    catch (Exception ex) 
    {
    MessageBox.Show(ex.Message, ThisApplication.Name);
    }
 
    // Добавляем нестандартное свойство
    try 
    {
    // Удаляем свойство, если оно существует
    prp = prps["Project Name"];
    prp.Delete();
    } 
    catch
    {
    // При генерации исключения ничего не делаем
    }
    try 
    {
    // Добавляем новое свойство
    prp = prps.Add("Project Name", false, 
      Office.MsoDocProperties.msoPropertyTypeString,   
      "White Papers", Type.Missing);
    } 
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message, ThisApplication.Name);
    }
  } 
  finally 
  {
    ThisApplication.ScreenUpdating = true;
  }
}
 
private int DumpPropertyCollection(
  Office.DocumentProperties prps, Excel.Range rng, int i) 
{
  foreach (Office.DocumentProperty prp in prps)
  {
    rng.get_Offset(i, 0).Value2 = prp.Name;
    try 
    {
    if (prp.Value != null ) 
    {
      rng.get_Offset(i, 1).Value2 = 
        prp.Value.ToString();
    }
    } 
    catch
    {
    // Вообще ничего не делаем
    }
    i += 1;
  }
  return i;
}

Совет В этом примере кода, DisplayDocumentProperties, используется несколько перечислимых и типов из сборки Microsoft.Office.Core и содержатся операторы Imports/using, которые задают, что "Office" является сокращенным обозначением этого пространства имен - так же, как это делается для сокращения "Excel". Но сокращение "Excel" задается шаблоном проекта автоматически, а сокращение "Office" вы должны добавлять вручную.

Рис. 8. Встроенные свойства документа

Примечание Хотя здесь вы работаете с Excel и его объектами, список доступных встроенных свойств документа предоставляется Office, и в Excel могут быть реализованы не все эти свойства. При попытке обратиться к свойству Value неопределенного свойства генерируется исключение. Ввиду этого в примере выполняется простая обработка исключений.

Работа со стилями

Как и в документах Word, в рабочих книгах Excel можно применять к областям именованные стили. Кроме того, в Excel есть ряд предопределенных (хотя и не особо интересных) стилей. Выбрав команду Format | Styles, можно открыть диалоговое окно, позволяющее интерактивно изменять стили (рис. 9).

Рис. 9. Интерактивное изменение стилей в диалоговом окне

Если в диалоговом окне Style щелкнуть Modify, откроется диалоговое окно Format Cells, показанное на рис. 10.

Рис. 10. Изменение стилей в диалоговом окне Format Cells

В диалоговом окне Format Cells показывается, какие параметры можно задавать при форматировании ячеек. Каждый из этих параметров доступен и программно. Для работы со стилями и применения стилей к диапазонам рабочей книги используйте свойство Styles объекта Workbook.

Это свойство позволяет создавать, изменять и удалять стили. По щелчку Apply Style в примере рабочей книги выполняется процедура, которая создает новый стиль (или использует существующий, если этот код уже выполнялся), задает различные параметры стиля и применяет его к области:

' Visual Basic
Private Sub ApplyStyle()
  Const STYLE_NAME As String = "PropertyBorder"
  Dim rng As Excel.Range
  ' Получаем диапазон, содержащий все свойства документа
  rng = GetDocPropRange()
 
  Dim sty As Excel.Style
  Try
    sty = ThisWorkbook.Styles(STYLE_NAME)
  Catch
    sty = ThisWorkbook.Styles.Add(STYLE_NAME)
  End Try
 
  sty.Font.Name = "Verdana"
  sty.Font.Size = 12
  sty.Font.Color = ColorTranslator.ToOle(Color.Blue)
  sty.Interior.Color = ColorTranslator.ToOle(Color.LightGray)
  sty.Interior.Pattern = XlPattern.xlPatternSolid
  rng.Style = STYLE_NAME
 
  rng.Columns.AutoFit()
End Sub
 
// C#
private void ApplyStyle()
{
  const String STYLE_NAME = "PropertyBorder";
  // Получаем диапазон, содержащий все свойства документа
  Excel.Range rng = GetDocPropRange();
  Excel.Style sty;
  try
  {
    sty = ThisWorkbook.Styles[STYLE_NAME];
  }
  catch
  {
    sty = ThisWorkbook.Styles.Add(STYLE_NAME, Type.Missing);
  }
 
  sty.Font.Name = "Verdana";
  sty.Font.Size = 12;
  sty.Font.Color = ColorTranslator.ToOle(Color.Blue);
  sty.Interior.Color = ColorTranslator.ToOle(Color.LightGray);
  sty.Interior.Pattern = Excel.XlPattern.xlPatternSolid;
  rng.Style = STYLE_NAME;
  rng.Columns.AutoFit();
}

Метод GetDocPropRange возвращает диапазон со списком свойств документа. В этой процедуре вызывается метод Range.End, чтобы найти конец такого диапазона, а затем создается новый диапазон по заданным левому верхнему и правому нижнему углам:

' Visual Basic
Private Function GetDocPropRange() As Excel.Range
  Dim rng As Excel.Range = _
  ThisApplication.Range("DocumentProperties")
 
  Dim rngStart As Excel.Range = _
  DirectCast(rng.Cells(1, 1), Excel.Range)
  Dim rngEnd As Excel.Range = _
  rng.End(Excel.XlDirection.xlDown).Offset(0, 1)
 
  Return ThisApplication.Range(rngStart, rngEnd)
End Function
 
// C#
private Excel.Range GetDocPropRange()
{
  Excel.Range rng = 
    ThisApplication.get_Range("DocumentProperties", Type.Missing);
  Excel.Range rngStart = 
    (Excel.Range) rng.Cells[1, 1];
  Excel.Range rngEnd = 
    rng.get_End(Excel.XlDirection.xlDown).get_Offset(0, 1);
  return ThisApplication.get_Range(rngStart, rngEnd);
}

Совет Подробнее о получении объектов Range и их использовании см. в разделе "Работа с диапазонами" далее в этом документе.

После запуска этого кода у области рабочей книги примера, содержащей свойства документа, изменятся заливка и шрифт (рис. 11).

Рис 11. Результат применения нестандартного стиля

По щелчку Clear Style запускается процедура, которая удаляет стиль той же области:

' Visual Basic
Private Sub ClearStyle()
  ' Получаем диапазон со списком всех свойств документа
  ' и удаляем стиль
  GetDocPropRange().Style = "Normal"
End Sub
 
// C#
private void ClearStyle()
{
  // Получаем диапазон со списком всех свойств документа
  // и удаляем стиль
  GetDocPropRange().Style = "Normal";
}

Работа с листами

Свойство Sheets класса Workbook возвращает объект Sheets. Этот объект содержит набор объектов Sheet, каждый из которых относится либо к Worksheet, либо к Chart. По щелчку List Sheets в рабочей книге примера выполняется процедура, которая перечисляет все листы в рабочей книге:

' Visual Basic
Private Sub ListSheets()
  Dim sh As Excel.Worksheet
  Dim rng As Excel.Range
  Dim i As Integer
 
  rng = ThisApplication.Range("Sheets")
  For Each sh In ThisWorkbook.Sheets
    rng.Offset(i, 0).Value = sh.Name
    i = i + 1
  Next sh
End Sub
 
// C#
private void ListSheets()
{
  int i = 0;
 
  Excel.Range rng = 
    ThisApplication.get_Range("Sheets", Type.Missing);
  foreach (Excel.Worksheet sh in ThisWorkbook.Sheets)
  {
    rng.get_Offset(i, 0).Value2 = sh.Name;
    i = i + 1;
  }
}

Кроме того, в классе Sheets есть и другие полезные члены, перечисленные ниже.

  • Свойство Visible позволяет показать или скрыть существующий лист без его удаления и повторного создания. Оно принимает значения перечислимого типа XlSheetVisibility (XlSheetHidden, XlSheetVeryHidden, xlSheetVisible). При значении XlSheetHidden пользователи могут увидеть скрытый лист средствами UI, а при значении XlSheetVeryHidden для отображения скрытой таблицы нужно выполнить код:
    ' Visual Basic
    DirectCast(ThisWorkbook.Sheets(1), Excel.Worksheet).Visible = _
      Excel.XlSheetVisibility.xlSheetVeryHidden
     
    // C#
    ((Excel.Worksheet) ThisWorkbook.Sheets[1]).Visible = 
      Excel.XlSheetVisibility.xlSheetVeryHidden;
    
  • Метод Add позволяет добавить новый лист в набор листов рабочей книги и принимает четыре необязательных параметра, задающих местонахождение листа, количество добавляемых листов и тип листа (рабочий лист, диаграмма и т. д.):
    ' Visual Basic
    Dim sh As Excel.Sheet = ThisWorkbook.Sheets.Add()
     
    // C#
    Excel.Sheet sh = ThisWorkbook.Sheets.Add(
      Type.Missing, Type.Missing, Type.Missing, Type.Missing);
    
  • Метод Copy создает копию листа и вставляет лист в заданное место. Вы можете по своему усмотрению вставить новый лист до или после существующего листа. По умолчанию Excel создает новую рабочую книгу, содержащую новый лист. В следующем фрагменте кода копируется первый лист рабочей книги, и копия помещается после третьего листа:
    ' Visual Basic
    DirectCast(ThisWorkbook.Sheets(1), Excel.Worksheet). _
      Copy(After:=ThisWorkbook.Sheets((3)))
     
    // C#
    ((Excel.Worksheet) ThisWorkbook.Sheets[1]).
      Copy(Type.Missing, ThisWorkbook.Sheets[3]);.
    
  • Метод Delete удаляет заданный лист:
    ' Visual Basic
    DirectCast(ThisWorkbook.Sheets(1), Excel.Worksheet).Delete
     
    // C#
    ((Excel.Worksheet) ThisWorkbook.Sheets[1]).Delete();
    
  • Метод FillAcrossSheets копирует данные из диапазона одного листа во все другие листы рабочей книги. Вы должны указать диапазон и что именно копировать - данные, параметры форматирования или и то, и другое. Остальное сделает Excel. В следующем фрагменте кода данные и параметры форматирования диапазона с именем Data копируются с одного листа во все листы рабочей книги:
    ' Visual Basic
    ThisWorkbook.Sheets.FillAcrossSheets( _
      ThisApplication.Range("Data"), Excel.XlFillWith.xlFillWithAll)
     
    // C#
    ThisWorkbook.Sheets.FillAcrossSheets(
      ThisApplication.get_Range("Data", Type.Missing), 
      Excel.XlFillWith.xlFillWithAll);
    
  • Метод Move во многом аналогичен методу Copy за исключением того, что в нем не создается новый экземпляр листа, а переносится существующий. Можно указать лист, перед которым помещается переносимый лист, или лист, после которого он помещается (но не тот и другой сразу). А по умолчанию Excel, как и в случае Copy, создает новую рабочую книгу, содержащую этот лист. В следующем фрагменте первый рабочий лист делается последним:
    ' Visual Basic
    Dim shts As Excel.Sheets = ThisWorkbook.Sheets
    DirectCast(shts(1), Excel.Worksheet).Move(After:=shts(shts.Count))
     
    // C#
    Excel.Sheets shts = ThisWorkbook.Sheets;
    ((Excel.Worksheet)shts[1]).Move(Type.Missing, shts[shts.Count]);
    

    Совет Если по каким-то причинам вы хотите отсортировать листы рабочей книги, это можно сделать методом Move, который выполняет весьма неэффективную пузырьковую сортировку (bubble sort). Конечно, скорость сортировки не критична, так как вряд ли у вас будет много листов.

  • Метод PrintOut позволяет распечатать выбранный объект (метод применим к нескольким разным объектам). Вы можете задать ряд дополнительных параметров: печатаемые страницы (с какой по какую), число копий, нужен ли предварительный просмотр перед печатью, имя используемого принтера, нужна ли печать в файл, требуется ли разбор по копиям (collate), а также имя файла, в который выполняется печать. В следующем примере печатается заданный лист, причем на принтер выводится лишь первая страница в двух экземплярах, перед печатью выполняется предварительный просмотр и используется принтер по умолчанию:
    ' Visual Basic
    DirectCast(ThisWorkbook.Sheets(1), Excel.Worksheet). _
      PrintOut(From:=1, To:=1, Copies:=2, Preview:=True)
     
    // C#
    ((Excel.Worksheet)ThisApplication.Sheets[1]).
      PrintOut(1, 1, 2, true, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing);
    
  • Метод PrintPreview позволяет показать заданный объект в окне PrintPreview; при необходимости можно запретить изменения в разметке (layout) страницы:
    ' Visual Basic
    DirectCast(ThisWorkbook.Sheets(1), Excel.Worksheet). _
      PrintPreview(False)
     
    // C#
    ((Excel.Worksheet)ThisApplication.Sheets[1]).PrintPreview(false);
    
  • Метод Select выделяет заданный объект, перемещая выделение, сделанное пользователем. (Чтобы передать фокус объекту, не меняя пользовательское выделение, вызывайте метод Activate.) При необходимости можно передать ссылку на объект, замещаемый текущим выделением. В следующем фрагменте выделяется первый рабочий лист:
    ' Visual Basic
    ActiveWorkbook.Sheets(1).Select()
     
    // C#
    ((Excel.Worksheet)ThisApplication.Sheets[1]).Select(Type.Missing);
    

Совет Многие методы, перечисленные в этом разделе, относятся и к другим классам. Так, метод PrintOut есть у классов Chart, Charts, Range, Sheets, Window, Workbook, Worksheet и Worksheets. Для каждого класса методы работают одинаково - отличаются лишь объекты, к которым они применяются. Метод Select применим практически к любому объекту, который можно выделить (а таких объектов немало).

Методы класса Workbook

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

  • Метод Activate активизирует рабочую книгу и выбирает первый лист рабочей книги:
    ' Visual Basic
    ThisApplication.Workbooks(1).Activate
     
    // C#
    ThisApplication.Workbooks[1].Activate;
    
  • Метод Close закрывает заданную рабочую книгу; при необходимости можно указать, требуется ли сохранение изменений. Если рабочую книгу еще ни разу не сохраняли, можно задать имя файла. Кроме того, если рабочая книга передается другим пользователям, укажите, следует ли отправлять рабочую книгу очередному пользователю. В следующем фрагменте кода рабочая книга закрывается без сохранения изменений:
    ' Visual Basic
    ThisApplication.Workbooks(1).Close(SaveChanges:=False)
     
    // C#
    ThisApplication.Workbooks(1).Close(false, 
      Type.Missing, Type.Missing);
    
  • Методы Protect и Unprotect соответственно устанавливают защиту для рабочей книги (при этом запрещается добавление или удаление рабочих листов) и снимают ее. Если надо, укажите пароль, а также задайте, следует ли защищать структуру (чтобы пользователи не могли перемещать листы) и окна рабочей книги. Защита рабочей книги не запрещает редактировать ячейки. Для защиты данных нужно защищать рабочие листы. Чтобы снять защиту рабочей книги, вызовите метод Unprotect и при необходимости передайте пароль. В следующем примере предполагается, что существует процедура GetPasswordFromUser, которая предлагает пользователю ввести пароль и возвращает его значение:
    ' Visual Basic
    ThisApplication.Workbooks(1).Protect(GetPasswordFromUser())
     
    // C#
    ThisApplication.Workbooks[1].Protect(
      GetPasswordFromUser(), Type.Missing, Type.Missing);
    
  • Метод Save, как легко догадаться, сохраняет рабочую книгу. Если рабочую книгу еще не сохраняли, следует вместо этого метода вызывать SaveAs, чтобы указать путь (иначе Excel сохранит ее в текущей папке под именем, присвоенным при создании):
    ' Visual Basic
    ' Сохраняем все открытые рабочие книги
    Dim wb As Excel.Workbook
    For Each wb in ThisApplication.Workbooks
      wb.Save
    Next wb
     
    // C#
    // Сохраняем все открытые рабочие книги
    foreach (Excel.Workbook wb in ThisApplication.Workbooks)
    {
      wb.Save();
    } 
    
  • Метод SaveAs значительно сложнее метода Save. Он позволяет сохранить заданную рабочую книгу и при необходимости указать ее имя, формат файла, пароль, режим доступа и т. д. Все параметры метода см. в справочной системе. В следующем фрагменте рабочая книга сохраняется в XML-формате в заданной папке:
    ' Visual Basic
    ThisApplication.ActiveWorkbook.SaveAs("C:\MyWorkbook.xml", _
     FileFormat:=Excel.XlFileFormat.xlXMLSpreadsheet)
     
    // C#
    ThisApplication.ActiveWorkbook.SaveAs("C:\\MyWorkbook.xml", 
      Excel.XlFileFormat.xlXMLSpreadsheet, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, 
      Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing);
    

    Совет Перед вызовом метода SaveAs может потребоваться присвоить свойству Application.DisplayAlerts значение False, так как при сохранении в некоторых форматах требуется взаимодействие с пользователем. Например, при сохранении рабочего листа в XML-формате Excel напоминает, что вы не сможете сохранить VBA-проект вместе с рабочей книгой. Если присвоить свойству DisplayAlerts значение False, это сообщение подавляется.

  • Метод SaveCopyAs сохраняет копию рабочей книги в файле, но не изменяет открытую рабочую книгу в памяти. Метод удобен для создания резервной копии без изменения местонахождения рабочей книги:
    ' Visual Basic
    ThisApplication.ActiveWorkbook.SaveCopyAs("C:\Test.xls")
     
    // C#
    ThisApplication.ActiveWorkbook.SaveCopyAs("C:\\Test.xls");
    

Внимание Интерактивная отмена любого метода, сохраняющего или копирующего рабочую книгу, приводит к генерации в коде ошибки пеирода выполнения. Например, если ваша процедура вызывает метод SaveAs, не отключая предупреждения Excel, а пользователь при получении предупреждения нажимает Cancel, то Excel генерирует ошибку периода выполнения и передает ее вашему коду.

Класс Worksheet

Итак, вы уже познакомились с большинством понятий, необходимых для операций с отдельными рабочими листами. Хотя класс Worksheet предоставляет много членов, большинство его свойств, методов и событий аналогично членам классов Application и/или Workbook. В этом разделе основное внимание уделяется важнейшим членам и специфике класса Worksheet, которые еще не рассматривались в документе. (Образцы исходного кода к этому разделу вы найдете в примере рабочей книги на листе Worksheet Object.)

Класса Sheet нет

В Excel есть набор Sheets объекта Workbook, но класса Sheet в Excel нет. Каждый член набора Sheets является или объектом Worksheet, или объектом Chart. Считайте Worksheet и Chart специализированными экземплярами внутреннего класса Sheet (точно сказать, так ли это на самом деле, может лишь тот, кому доступен исходный код), к которому нет открытого доступа.

Защита данных

Обычно защита данных в Excel заключается в том, что пользователям и/или коду запрещают изменять объекты рабочего листа. Если включена защита рабочего листа, то по умолчанию пользователи не могут редактировать или еще каким-то изменять лист. В UI для установки защиты предназначена команда Tools | Protection | Protect Sheet. При выборе этого пункта открывается диалоговое окно Protect Sheet (рис. 12). В нем можно задать пароль или разрешить пользователям выполнять определенные действия. По умолчанию после установки защиты блокируются все ячейки. Вы можете разрешить редактировать определенные диапазоны. Для этого служит команда Tools | Protection | Allow Users to Edit Ranges, открывающая диалоговое окно, как на рис. 13. С помощью этих двух диалоговых окон можно заблокировать лист, а затем разрешить редактировать определенные диапазоны и выполнять конкретные операции редактирования.

Рис. 12. Это диалоговое окно, управляющее защитой, вызывается из UI

Рис. 13. С помощью этого диалогового окна можно разрешить редактировать определенные диапазоны

Для программного управления защитой листа используйте метод Protect листа. Метод имеет следующий синтаксис, причем все параметры являются необязательными:

' Visual Basic
WorksheetObject.Protect(Password, DrawingObjects, Contents, _
  Scenarios, UserInterfaceOnly, AllowFormattingCells, _
  AllowFormattingColumns, AllowFormattingRows, _
  AllowInsertingColumns, AllowInsertingRows, _
  AllowInsertingHyperlinks, AllowDeletingColumns, _
  AllowDeletingRows, AllowSorting, AllowFiltering, _
  AllowUsingPivotTables)
 
// C#
WorksheetObject.Protect(Password, DrawingObjects, Contents, 
  Scenarios, UserInterfaceOnly, AllowFormattingCells, 
  AllowFormattingColumns, AllowFormattingRows, 
  AllowInsertingColumns, AllowInsertingRows, 
  AllowInsertingHyperlinks, AllowDeletingColumns, 
  AllowDeletingRows, AllowSorting, AllowFiltering, 
  AllowUsingPivotTables);

Ниже перечислены параметры метода Protect.

  • Параметр Password задает чувствительную к регистру букв строку, которую надо будет указывать для снятия защиты рабочего листа. Без этого параметра снять защиту сможет кто угодно.
  • Параметр DrawingObjects, равный True, устанавливает защиту геометрических фигур (shapes), находящихся на рабочем листе. Значение по умолчанию - False.
  • Параметр Contents, равный True, устанавливает защиту содержимого (ячеек) рабочего листа. Значение по умолчанию - True, и вряд ли вам понадобится его менять.
  • Параметр Scenarios, равный True, устанавливает защиту сценариев рабочего листа. Значение по умолчанию - True.
  • Параметр UserInterfaceOnly, равный True, разрешает выполнять изменения программно, но не из UI. По умолчанию параметр равен False, и это означает, что защищенный рабочий лист нельзя изменять ни программно, ни средствами UI. Значение этого свойства относится только к текущему сеансу. Если нужно, чтобы код мог изменять рабочей лист во время любого сеанса, пишите код, присваивающий значение свойству при каждом открытии рабочей книги.
  • AllowFormattingCells, AllowFormattingColumns и прочие параметры в полном синтаксисе метода разрешают операции форматирования, которые соответствуют параметрам в диалоговом окне на рис. 12. По умолчанию все эти свойства равны False.
  • Чтобы защитить рабочий лист, вызовите метод Protect; в следующем фрагменте при вызове этого метода задается пароль и разрешается только сортировка:
    ' Visual Basic
    DirectCast(ThisApplication.Sheets(1), Excel.Worksheet). _
      Protect("MyPassword", AllowSorting:=True)
     
    // C#
    ((Excel.Worksheet)ThisApplication.Sheets[1]).Protect(
      "MyPassword", Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
      Type.Missing, true, Type.Missing, Type.Missing);
    

Совет Очевидно, что "зашивать" пароль в код - идея не лучшая. Скорее всего вам придется запрашивать пароль у пользователя и применять его к рабочей книге без сохранения.

Чтобы снять защиту с рабочего листа, можно написать код следующего вида (здесь предполагается, что у вас есть процедура GetPasswordFromUser, которая запрашивает у пользователя пароль и возвращает его значение):

' Visual Basic
DirectCast(ThisApplication.Sheets(1), Excel.Worksheet). _
  Unprotect(GetPasswordFromUser())
 
// C#
((Excel.Worksheet)ThisApplication.Sheets[1]).
  Unprotect(GetPasswordFromUser());

Метод Unprotect снимает защиту с рабочего листа и принимает необязательный параметр - пароль.

В Excel есть еще два объекта, полезных при защите данных: Protection и AllowEditRange. Объект Protection инкапсулирует всю информацию, указываемую при вызове метода Protect, а также информацию о незащищенных диапазонах. При вызове метода Protect присваиваются значения свойствам общего объекта Protection. Этот объект предоставляет свойства типа Boolean, соответствующие параметрам метода Protect:

  • AllowDeletingColumns, AllowDeletingRows;
  • AllowFiltering;
  • AllowFormattingCells, AllowFormattingColumns, AllowFormattingRows;
  • AllowInsertingColumns, AllowInsertingHyperlinks, AllowInsertingRows;
  • AllowSorting;
  • AllowUsingPivotTables.

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

  • RangeВозвращает или устанавливает диапазон, соответствующий области, которую можно редактировать.
  • TitleВозвращает или присваивает название области, допускающей редактирование (показывается в диалоговом окне, как на рис. 13).
  • UsersВозвращает или устанавливает набор объектов UserAccess (описание объекта UserAccess см. в документации).

На листе Worksheet Object примера рабочей книги (рис. 14) можно поэкспериментировать с программной защитой. По щелчку Protect устанавливается защита: редактировать можно только две затененные области (два диапазона с именами Information и Date). По щелчку Unprotect защита с рабочего листа снимается.

Рис. 14. Пример защиты рабочего листа

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

' Visual Basic
Private Sub ProtectSheet()
  Dim ws As Excel.Worksheet = _
  DirectCast(ThisApplication.ActiveSheet, Excel.Worksheet)
 
  With ws.Protection.AllowEditRanges
    .Add("Information", ThisApplication.Range("Information"))
    .Add("Date", ThisApplication.Range("Date"))
  End With
  ws.Protect()
End Sub
 
Private Sub UnprotectSheet()
  Dim ws As Excel.Worksheet = _
  DirectCast(ThisApplication.Sheets("Worksheet Class"), _
  Excel.Worksheet)
 
  ' Снимаем защиту с листа
  ws.Unprotect()
 
  ' Удаляем все диапазоны защиты, чтобы их очистить.
  ' При удалении необходимо с помощью индекса перебрать
  ' эти объекты в обратном порядке. У данного набора нет
  ' перечислителя, а при переборе в обычном порядке
  ' изменение размера не учитывается.
  Dim i As Integer
  With ws.Protection.AllowEditRanges
    For i = .Count To 1 Step -1
    .Item(i).Delete()
    Next i
  End With
End Sub
 
// C#
 
private void ProtectSheet()
{
  Excel.Worksheet ws =
  (Excel.Worksheet)ThisApplication.ActiveSheet;
 
  Excel.AllowEditRanges ranges = ws.Protection.AllowEditRanges;
  ranges.Add("Information", 
    ThisApplication.get_Range("Information", Type.Missing), 
    Type.Missing);
  ranges.Add("Date", 
    ThisApplication.get_Range("Date", Type.Missing), Type.Missing);
 
  ws.Protect(Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing, Type.Missing,Type.Missing, Type.Missing, 
    Type.Missing,Type.Missing, Type.Missing, Type.Missing, 
    Type.Missing,Type.Missing,Type.Missing,
    Type.Missing,Type.Missing);
}
 
private void UnprotectSheet()
{
  Excel.Worksheet ws = 
    (Excel.Worksheet) ThisApplication.Sheets["Worksheet Class"];
  ws.Unprotect(Type.Missing);
 
  // Удаляем все диапазоны защиты, чтобы их очистить.
  // При удалении необходимо с помощью индекса перебрать
  // эти объекты в обратном порядке. У данного набора нет
  // перечислителя, а при переборе в обычном порядке
  // изменение размера не учитывается.
 
  Excel.AllowEditRanges ranges = ws.Protection.AllowEditRanges;
  for (int i = ranges.Count; i >= 1; i--)
  {
    ranges[i].Delete();
  }
}

Свойства, возвращающие объекты

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

Примечания

Выбрав Insert | Comment, можно вставить текстовое примечание, присоединенное к диапазону рабочего листа (рис. 15). Кроме того, можно выполнить эту операцию программно, вызовом метода AddComment объекта Range. Следующий код удаляет примечание, присоединенное к диапазону Date (если оно есть), а затем создает новое примечание. Далее вызовом метода ShowOrHideComments, описанного в следующем примере кода, показываются все примечания листа (рис. 16):

' Visual Basic
Dim rng As Excel.Range = ThisApplication.Range("Date")
If Not rng.Comment Is Nothing Then
  rng.Comment.Delete()
End If
rng.AddComment("Comment added " & DateTime.Now)
 
' Показываем все примечания
ShowOrHideComments(Show:=True)
 
// C#
Excel.Range rng = ThisApplication.get_Range("Date", Type.Missing);
if (rng.Comment != null ) 
{
  rng.Comment.Delete();
}
rng.AddComment("Comment added " + DateTime.Now);
 
// Показываем все примечания
ShowOrHideComments(true);

Рис. 15. Вставить примечание средствами UI несложно

Рис. 16. На листе примера показаны все примечания

Класс Worksheet предоставляет свойство Comments, возвращающее объект Comments. Это набор объектов Comment, позволяющий перебирать в цикле все объекты Comment, связанные с Worksheet. У класса Comment не так уж много членов. Вы скорее всего будете использовать свойство Visible класса Comment, чтобы показать или скрыть примечание, и метод Delete, чтобы удалить примечание. Кроме того, может оказаться полезным метод Text: он позволяет поместить текст в примечание, добавив его в конец или перезаписав существующий текст.

Добавив примечание, вы, вероятно, захотите показать примечания на рабочем листе. В проекте-примере имеется процедура ShowOrHideComments, которая показывает или скрывает примечания на активном листе:

' Visual Basic
Private Sub ShowOrHideComments(ByVal Show As Boolean)
  ' Показываем или скрываем все примечания
  Dim ws As Excel.Worksheet = _
  DirectCast(ThisApplication.Sheets("Worksheet Class"), _
  Excel.Worksheet)
 
  Dim i As Integer
  For i = 1 To ws.Comments.Count
    ws.Comments(i).Visible = Show
  Next
End Sub
 
// C#
private void ShowOrHideComments(bool show)
{
  // Показываем или скрываем все примечания
  Excel.Worksheet ws = 
    (Excel.Worksheet) ThisApplication.Sheets["Worksheet Class"];
 
  for (int i = 1; i <= ws.Comments.Count; i++)
  {
    ws.Comments[i].Visible = show;
  }
}

Примечание У набора Comments, как и многих других вспомогательных классов-наборов Excel, нет перечислителя (enumerator) по умолчанию. Другими словами, для обработки всех элементов набора нельзя воспользоваться циклом For Each. При работе с наборами, подобными Comment, нужен цикл по индексу.

Структурирование

В Excel можно группировать строки данных с помощью средств работы со структурами (outlining). Те же средства доступны и программно. Например, для строк, показанных на рис. 17, можно создать структуру (на иллюстрации это уже сделано), а потом свернуть строки (рис. 18) и группы (рис. 19).

Рис. 17. Создание групп

Рис. 18. Свернутые группы

Рис. 19. Полностью свернутые группы

Класс Worksheet поддерживает свойство Outline, которое само является объектом Outline. У класса Outline не слишком много членов. Ниже перечислены те из них, которые понадобятся вам с наибольшей вероятностью.

  • AutomaticStyles (BooleanУказывает, должен ли ) Excel применять к структурам автоматические стили.
  • SummaryColumn (XlSummaryColumnВозвращает или устанавливает ) местонахождение итоговых столбцов. У перечислимого XlSummaryColumn два возможных значения: xlSummaryOnLeft и xlSummaryOnRight.
  • SummaryRow (XlSummaryRowВозвращает или устанавливает ) местонахождение итоговых строк. У перечислимого XlSummaryRow два возможных значения: xlSummaryAbove и xlSummaryBelow.
  • ShowLevelsПозволяет свертывать или развертывать группы структуры на том уровне строки и/или столбца, который вам нужен. Методу можно передать два параметра, как, например, в следующем фрагменте:
' Visual Basic
Dim ws As Excel.Worksheet = _
  DirectCast(ThisApplication.ActiveSheet, Excel.Worksheet)
' Передаем параметры RowLevels и/или ColumnLevels
ws.Outline.ShowLevels(RowLevels:=3)
 
// C#
Excel.Worksheet ws = 
  (Excel.Worksheet) ThisApplication.ActiveSheet;
 
// Передаем параметры RowLevels и/или ColumnLevels
ws.Outline.ShowLevels(3, Type.Missing);

В примере рабочего листа содержатся диапазоны, соответствующие данным за 2001 г. (Data2001) и 2002 г. (Data2002), а также всему набору строк (AllData). Эти именованные диапазоны охватывают всю ширину рабочего листа; чтобы группирование работало, используйте диапазоны, содержащие полные строки. С данными за 2003 г. именованный диапазон не связан. Это сделано, чтобы показать, как работать с полными строками как с диапазонами.

Создать группы просто: достаточно вызвать метод Group диапазона, соответствующего одной или нескольким полным строкам. (Можно указать четыре необязательных параметра группирования: начальное и конечное группируемые значения, группу по значению и дополнительный массив значений типа Boolean, задающих периоды группирования. В примере ни один из этих параметров не используется.) Для удаления группы вызывается метод Ungroup. Например, по щелчку ссылки Work with Groups на листе примера выполняется следующий код:

' Visual Basic
Private Sub WorkWithGroups()
  Dim ws As Excel.Worksheet = _
  DirectCast(ThisApplication.ActiveSheet, Excel.Worksheet)
 
  ' Задаем параметры группирования уровня рабочего листа.
  ' В данном случае итоговые строки находятся под
  ' строками данных (т. е. Excel известно, куда помещать
  ' итоговые строки), а форматирование итоговых строк
  ' не требуется - оно уже выполнено.
  ws.Outline.SummaryRow = Excel.XlSummaryRow.xlSummaryBelow
  ws.Outline.AutomaticStyles = False
 
  ' Группируем два именованных диапазона, каждый
  ' из которых является группой полных строк
  ThisApplication.Range("Data2001").Group()
  ThisApplication.Range("Data2002").Group()
  ThisApplication.Range("AllData").Group()
 
  ' Диапазон строк от 24 до 27 не является именованным,
  ' поэтому работаем с этим диапазоном напрямую
  Dim rng As Excel.Range = _
  DirectCast(ws.Rows("24:27"), Excel.Range)
  rng.Group()
 
  ' Свертываем до групп второго уровня
  ws.Outline.ShowLevels(RowLevels:=2)
End Sub
 
// C#
private void WorkWithGroups()
{
  Excel.Worksheet ws = 
    (Excel.Worksheet) ThisApplication.ActiveSheet;
 
  // Задаем параметры группирования уровня рабочего листа.
  // В данном случае итоговые строки находятся под
  // строками данных (т. е. Excel известно, куда помещать
  // итоговые строки), а форматирование итоговых строк
  // не требуется - оно уже выполнено.
  ws.Outline.SummaryRow = Excel.XlSummaryRow.xlSummaryBelow;
  ws.Outline.AutomaticStyles = false;
 
  // Группируем два именованных диапазона, каждый
  // из которых является группой полных строк
  ThisApplication.get_Range("Data2001", Type.Missing).
    Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
  ThisApplication.get_Range("Data2002", Type.Missing).
    Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
  ThisApplication.get_Range("AllData", Type.Missing).
    Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
 
  // Диапазон строк от 24 до 27 не является именованным,
  // поэтому работаем с этим диапазоном напрямую
  Excel.Range rng = (Excel.Range)ws.Rows["24:27", Type.Missing];
  rng.Group(Type.Missing, Type.Missing, Type.Missing, 
  Type.Missing);
 
  // Свертываем до групп второго уровня
  ws.Outline.ShowLevels(2, Type.Missing);
}

Чтобы сгруппировать три именованных диапазона, просто вызывается метод Group диапазона:

' Visual Basic
ThisApplication.Range("Data2001").Group()
 
// C#
ThisApplication.get_Range("Data2001", Type.Missing).
  Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);

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

' Visual Basic
Dim rng As Excel.Range = _
  DirectCast(ws.Rows("24:27"), Excel.Range)
rng.Group()
 
// C#
Excel.Range rng = (Excel.Range)ws.Rows["24:27", Type.Missing];
rng.Group(Type.Missing, Type.Missing, Type.Missing, Type.Missing);

По щелчку ссылки Clear Groups на примере рабочего листа запускается аналогичный код, очищающий группы:

' Visual Basic
Private Sub ClearGroups()
  Dim ws As Excel.Worksheet = _
  DirectCast(ThisApplication.ActiveSheet, Excel.Worksheet)
 
  ' Задаем параметры RowLevels и/или ColumnLevels
  ws.Outline.ShowLevels(RowLevels:=3)
 
  Dim rng As Excel.Range = _
  DirectCast(ws.Rows("24:27"), Excel.Range)
  rng.Ungroup()
 
  ThisApplication.Range("Data2001").Ungroup()
  ThisApplication.Range("Data2002").Ungroup()
  ThisApplication.Range("AllData").Ungroup()
End Sub
 
// C#
private void ClearGroups()
{
  Excel.Worksheet ws = 
    (Excel.Worksheet) ThisWorkbook.Sheets["Worksheet Class"];
 
  // Задаем параметры RowLevels и/или ColumnLevels
  ws.Outline.ShowLevels(3, Type.Missing);
 
  Excel.Range rng = (Excel.Range) ws.Rows["24:27", Type.Missing];
  rng.Ungroup();
 
  ThisApplication.get_Range("Data2001", Type.Missing).Ungroup();
  ThisApplication.get_Range("Data2002", Type.Missing).Ungroup();
  ThisApplication.get_Range("AllData", Type.Missing).Ungroup();
}

Используя этот прием, можно создавать и удалять группы, а также управлять уровнем группирования при отображении данных на рабочих листах.

Объект Range

Объект Range применяется в большинстве приложений Excel; чтобы выполнить операцию с какой-либо областью Excel, вы должны сначала представить ее в виде объекта Range и работать уже с ним, обращаясь к свойствам и методам этого объекта. Класс Range крайне важен; объекты Range так или иначе используются практически в каждом примере, встретившемся вам в этом документе. Объект Range представляет ячейку, строку, столбец, выборку ячеек, содержащую один или несколько блоков ячеек (которые не обязательно должны быть смежными) и даже группу ячеек из разных листов.

Так как описать все члены огромного класса Range невозможно, в этом разделе рассматриваются три основных вопроса:

  • программное обращение к диапазонам;
  • программное управление диапазонами;
  • применение объекта Range для решения специфических задач.

    Другими словами, поскольку объект Range находит очень много применений в самых разных ситуациях, в этом разделе вместо рассмотрения полного списка членов основное внимание уделяется вопросу "Как сделать то-то и то-то?".

    Управление выделением

    Как ни соблазнительно работать с текущим выделением, используя его для изменения свойств и поведения диапазонов, лучше этого не делать. Как и любой другой общий ресурс, выделение в Excel является пользовательским. Если изменять его программно, пользователь теряет контроль над текущим выделением. Правило таково: вызывайте метод Select объекта, только если вы намерены применить его для изменения пользовательского выделения. Никогда не вызывайте Select лишь потому, что это удобно вам как разрабочику. Если нужно только задать значение свойства диапазона, всегда есть другие варианты. Отсутствие вызовов метода Select не только ускорит выполнение кода, но и сделает приложение более удобным для пользователей.

    Чтобы очистить область, смежную с текущей пользовательской ячейкой, можно было бы написать код вида: '

     Visual Basic
    ThisApplication.ActiveCell.CurrentRegion.Select
    DirectCast(ThisApplication.Selection, Excel.Range).ClearContents
     
    // C#
    ThisApplication.ActiveCell.CurrentRegion.Select();
    ((Excel.Range)ThisApplication.Selection).ClearContents();
    

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

    ' Visual Basic
    ThisApplication.ActiveCell.CurrentRegion.ClearContents
     
    // C#
    ThisApplication.ActiveCell.CurrentRegion.ClearContents();
    

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

    Совет Работая с ячейкой или группой ячеек по возможности используйте диапазон ячеек, которые вы хотите обработать, а не изменяйте выделение. Если вы собираетесь изменить пользовательское выделение, тогда вызывайте метод Range.Select.

    Программное обращение к диапазонам

    Класс Range настолько гибок, что при программной работе с диапазонами появляется слишком много вариантов. Иногда объект Range - это отдельный объект, а иногда он выступает в роли набора объектов. Хотя объект Range часто ссылается на одиночный объект, у него есть члены Item и Count, поэтому бывает сложно разобраться, как пользоваться объектом Range.

    Совет В нескольких последующих примерах считывается свойство Address диапазонов. Оно возвращает строку с представлением координат диапазона в одном из нескольких форматов, в частности "$A$1" (ячейка A1), "$1" (первая строка рабочего листа) и "$A$1:$C$5" (диапазон, который состоит из всех ячеек, принадлежащих прямоугольнику с координатами углов A1 и C5). Знак $ обозначает абсолютную координату (в отличие от относительной). Свойство Address - самый простой способ определить точное местоположение полученного диапазона. Подробнее о различных способах обращения к диапазону см. в справочной системе Excel.

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

    ' Visual Basic
    Dim ws As Excel.Worksheet = _
      DirectCast(ThisWorkbook.Worksheets(1), Excel.Worksheet)
    Dim rng, rng1, rng2 As Excel.Range
     
    // C#
    Excel.Worksheet ws = (Excel.Worksheet)ThisWorkbook.Worksheets[1];
    Excel.Range rng, rng1, rng2;
    

    Для ссылок на некий диапазон годится любой из следующих способов (есть и другие способы получить ссылку на объект Range).

    • Обратиться к свойству ActiveCell объекта Application:
      ' Visual Basic
      rng = ThisApplication.ActiveCell
       
      // C#
      rng = ThisApplication.ActiveCell;
      
    • Задействовать свойство Range объекта, указав диапазон. Поскольку параметризованные неиндексированные свойства в C# не поддерживаются, приходится вызывать метод get_Range, принимающий два параметра:
      ' Visual Basic
      rng = ws.Range("A1")
      rng = ws.Range("A1:B12")
       
      // C#
      rng = ws.get_Range("A1", Type.Missing);
      rng = ws.get_Range("A1:B12", Type.Missing);
      
    • Воспользоваться свойством Cells рабочего листа, указав значения строки и столбца:
      ' Visual Basic
      ' The Cells collection returns an Object--
      ' Convert it to a Range object explicitly:
      rng = DirectCast(ws.Cells(1, 1), Excel.Range)
       
      // C#
      rng = (Excel.Range)ws.Cells[1, 1];
      
    • Указать "углы" диапазона. Можно также напрямую ссылаться на свойство Cells, Rows или Columns диапазона; в каждом из этих случаев свойство возвращает диапазон:
      ' Visual Basic
      rng = ws.Range("A1", "C5")
      rng = ws.Range("A1", "C5").Cells
      rng = ws.Range("A1", "C5").Rows
      rng = ws.Range("A1", "C5").Columns
       
      // C#
      rng = ws.get_Range("A1", "C5");
      rng = ws.get_Range("A1", "C5").Cells;
      rng = ws.get_Range("A1", "C5").Rows;
      rng = ws.get_Range("A1", "C5").Columns;
      
    • Обратиться к именованному диапазону. Вы встречались с таким подходом во всем документе. Заметьте: поскольку в C# метод get_Range принимает два параметра, а для задания диапазона по имени достаточно одного, в качестве второго параметра передавайте Type.Missing:
      ' Visual Basic
      rng = ThisApplication.Range("SomeRangeName")
       
      // C#
      rng = ThisApplication.Range("SomeRangeName", Type.Missing);
      
    • Обратиться к заданной строке, столбцу или диапазону строк и столбцов; заметьте, что свойства Rows и Columns возвращают значения Object, поэтому, если параметр Option Strict установлен в On, необходимо преобразование типов:
      ' Visual Basic
      rng = DirectCast(ws.Rows(1), Excel.Range)
      rng = DirectCast(ws.Rows("1:3"), Excel.Range)
      rng = DirectCast(ws.Columns(3), Excel.Range)
       
      // C#
      rng = (Excel.Range)ws.Rows[1, Type.Missing];
      rng = (Excel.Range)ws.Rows["1:3", Type.Missing];
      rng = (Excel.Range)ws.Columns[3, Type.Missing];
      

      Внимание В случае свойства Columns функция IntelliSense сбивает с толку: показывает, что нужно задать значение строки, затем - столбца. А на самом деле значения для свойства Columns идут в обратном порядке. В свойствах Rows и Columns второй параметр не используется.

    • Через свойство Selection объекта Application получить диапазон, соответствующий выделенным ячейке или ячейкам; в случае, показанном на рис. 20, следующий фрагмент кода вернет "$C$3" ("$" означает, что координаты абсолютные):
      ' Visual Basic
      Debug.WriteLine( _
        DirectCast(ThisApplication.Selection, Excel.Range).Address)
       
      // C#
      System.Diagnostics.Debug.WriteLine(
        ((Excel.Range)ThisApplication.Selection).
        get_Address(Type.Missing, Type.Missing, 
        Excel.XlReferenceStyle.xlA1, Type.Missing, Type.Missing));
      

      Совет Свойство Address - еще одно параметризованное свойство, которое в C# не обрабатывается напрямую. Чтобы получить адрес, соответствующий объекту Range, вызовите метод get_Address. Все параметры свойства Address необязательны, а методу get_Address требуется передавать пять параметров; скорее всего вас заинтересует лишь третий параметр, задающий формат адреса.

    • Создать диапазон, содержащий объединение двух других диапазонов (указав два диапазона в кавычках через запятую):
      ' Visual Basic
      rng = ThisApplication.Range("A1:D4, F2:G5")
      ' Кроме того, можно применить метод Union объекта
      ' Application, чтобы получить объединение двух диапазонов
      rng1 = ThisApplication.Range("A1:D4")
      rng2 = ThisApplication.Range("F2:G5")
      rng = ThisApplication.Union(rng1, rng2)
       
      // C#
      rng = ThisApplication.get_Range("A1:D4, F2:G5", Type.Missing);
      // Кроме того, можно применить метод Union объекта
      // Application, чтобы получить объединение двух диапазонов,
      // но в C# это требует больше усилий
      rng1 = ThisApplication.get_Range("A1", "D4");
      rng2 = ThisApplication.get_Range("F2", "G5");
      // Заметьте: при вызове метода Union нужно
      // передать 30 параметров
      rng = ThisApplication.Union(rng1, rng2, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing);
      
    • Создать диапазон, являющийся пересечением двух других диапазонов (указав эти два диапазона в кавычках без разделителя):
      ' Visual Basic
      rng = ThisApplication.Range("A1:D16 B2:F14")
      ' Кроме того, чтобы получить пересечение двух диапазонов,
      ' можно вызвать метод Intersect объекта Application
      rng1 = ThisApplication.Range("A1:D16")
      rng2 = ThisApplication.Range("B2:F14")
      rng = ThisApplication.Intersect(rng1, rng2)
       
      // C#
      rng = ThisApplication.get_Range("A1:D16 B2:F14", Type.Missing);
      // Кроме того, чтобы получить пересечение двух диапазонов,
      // можно вызвать метод Intersect объекта Application. Заметьте,
      // что вызов Intersect требует передачи 30 параметров.
      rng1 = ThisApplication.get_Range("A1", "D16");
      rng2 = ThisApplication.get_Range("B2", "F14");
      rng = ThisApplication.Intersect(rng1, rng2, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing);
      
    • Воспользоваться свойством Offset диапазона, чтобы получить диапазон, заданный координатами относительно исходного диапазона; в следующем примере содержимое добавляется в область под ячейкой, находящейся в первой строке и первом столбце:
      ' Visual Basic
      rng = DirectCast(ws.Cells(1, 1), Excel.Range)
       
      Dim i As Integer
      For i = 1 To 5
        rng.Offset(i, 0).Value = i.ToString
      Next
       
      // C#
      rng = (Excel.Range) ws.Cells[1, 1];
      for (int i = 1; i <= 5; i++)
      {
        rng.get_Offset(i, 0).Value2 = i.ToString();
      }
      

      Совет Свойство Range.Offset - параметризованное, поэтому в коде на C# нельзя прочитать его значение напрямую. Разработчики на C# должны вызывать метод get_Offset.

    • Через свойство CurrentRegion диапазона получить диапазон, который представляет текущую область (ограниченную ближайшими пустыми строкой и столбцом); например, для рис. 20 следующий оператор изменит шрифт текущей области на полужирный:
      ' Visual Basic
      ThisApplication.Range("C3").CurrentRegion.Font.Bold = True
       
      // C#
      ThisApplication.get_Range("C3", Type.Missing).
        CurrentRegion.Font.Bold = True;
      

      Рис. 20. При запросе свойства CurrentRegion для ячейки C3 возвращается диапазон A1:E5
       

    • Через свойство Areas диапазона получить набор диапазонов, каждый из которых соответствует одной области содержимого диапазона. Например, следующий фрагмент кода выводит адреса двух областей именованного диапазона Test, показанного на рис. 21, - "$B$1:$E$5" и "$C$7:$G$11" ("$" обозначает абсолютные координаты):
      ' Visual Basic
      rng = ThisApplication.Range("Test")
      Dim i As Integer
      For i = 1 To rng.Areas.Count
        Debug.WriteLine(rng.Areas(i).Address)
      Next
       
      // C#
      rng = ThisApplication.get_Range("Test", Type.Missing);
      for (int i = 1; i <= rng.Areas.Count; i++)
      { 
        System.Diagnostics.Debug.WriteLine(
          rng.Areas[i].get_Address(Type.Missing, Type.Missing, 
          Excel.XlReferenceStyle.xlA1, Type.Missing, Type.Missing));
      }
      

      Рис 21. Диапазоны могут содержать несмежные области, и в этом случае, чтобы получить каждую область по отдельности, используйте свойство Areas
       

    • Задействовать свойство End, указав значение перечислимого XlDirection (xlUp, xlToRight, xlToLeft, xlDown), чтобы получить диапазон, являющийся ячейкой на границе области (как при нажатии комбинации клавиш Ctrl и стрелки соответствующего направления). Для ячейки, выделенной на рис. 22, следующий фрагмент кода вернет четыре диапазона, указанные в комментариях:
      ' Visual Basic
      Dim rngLeft, rngRight, rngUp, rngDown as Excel.Range
      rng = DirectCast(ThisApplication.Selection, Excel.Range)
      ' E3
      rngRight = rng.End(Excel.XlDirection.xlToRight)
      ' A3
      rngLeft = rng.End(Excel.XlDirection.xlToLeft)
      ' C1
      rngUp = rng.End(Excel.XlDirection.xlUp)
      ' C5
      rngDown = rng.End(Excel.XlDirection.xlDown)
       
      // C#
      Excel.Range rngLeft, rngRight, rngUp, rngDown;
      rng = (Excel.Range) ThisApplication.Selection;
      // Свойство Range.End - параметризованное, поэтому в C#
      // его нельзя прочитать. Приходится вызывать метод get_End
       
      // E3
      rngRight = rng.get_End(Excel.XlDirection.xlToRight);
      // A3
      rngLeft = rng.get_End(Excel.XlDirection.xlToLeft);
      // C1
      rngUp = rng.get_End(Excel.XlDirection.xlUp);
      // C5
      rngDown = rng.get_Down(Excel.XlDirection.xlDown);
      

      Рис. 22. Получение диапазонов, соответствующих границам диапазона, через свойство End
       

    • Через свойство EntireRow или EntireColumn обратиться к строке (строкам) или к столбцу (столбцам), содержащим заданный диапазон. Например, следующий фрагмент кода выделяет полужирным шрифтом строки с 7 по 11 в примере на рис. 21:
      ' Visual Basic
      rng = ThisApplication.Range("Test")
      rng.Areas(2).EntireRow.Font.Bold = True
       
      // C#
      rng = ThisApplication.get_Range("Test", Type.Missing);
      rng.Areas[2].EntireRow.Font.Bold = true;
      

    Выделение текущей строки шрифтом

    Разработчикам часто бывает нужно изменить начертание шрифта всей строки, содержащей выделенную ячейку, на полужирное. Эта функциональность не встроена в Excel, но ее несложно реализовать самостоятельно. Лист Range Class примера рабочей книги содержит диапазон, работающий по-особому: при выборе ячейки ее строка выделяется полужирным. На рис. 23 показано, как это выглядит.

    Рис. 23. При выборе ячейки вся ее строка выделяется полужирным

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

    ' Visual Basic
    Private Sub BoldCurrentRow(ByVal ws As Excel.Worksheet)
      ' Запоминаем предыдущую строку, выделенную полужирным
      Static intRow As Integer
     
      ' Работаем с текущей активной ячейкой
      Dim rngCell As Excel.Range = _
      ThisApplication.ActiveCell
     
      ' Выделяем полужирным текущую строку
      rngCell.EntireRow.Font.Bold = True
     
      ' Проверяем, что intRow<>0 (0 означает, что этот код
      ' выполняется первый раз)
      If intRow <> 0 Then
        ' Если текущая строка изменилась, меняем начертание
        ' шрифта прежней текущей строки на обычный
        If rngCell.Row <> intRow Then
        Dim rng As Excel.Range = _
          DirectCast(ws.Rows(intRow), Excel.Range)
        rng.EntireRow.Font.Bold = False
        End If
      End If
      ' Сохраняем номер строки для следующего раза
      intRow = rngCell.Row
    End Sub
     
    // C#
    private int LastBoldedRow = 0;
    private void BoldCurrentRow(Excel.Worksheet ws) 
    {
      // Запоминаем предыдущую строку, выделенную полужирным
     
      // Работаем с текущей активной ячейкой
      Excel.Range rngCell = ThisApplication.ActiveCell;
     
      // Выделяем полужирным текущую строку
      rngCell.EntireRow.Font.Bold = true;
     
      // Проверяем, что intRow<>0 (0 означает, что этот код
      // выполняется первый раз)
      if (LastBoldedRow != 0) 
      {
        // Если текущая строка изменилась, меняем начертание
        // шрифта прежней текущей строки на обычный
        if (rngCell.Row != LastBoldedRow) 
        {
        Excel.Range rng = 
          (Excel.Range)ws.Rows[LastBoldedRow, Type.Missing];
        rng.Font.Bold = false;
        }
      }
      // Сохраняем номер строки для следующего раза
      LastBoldedRow = rngCell.Row;
    }
    

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

    • Объявляется переменная (static в Visual Basic) для хранения номера ранее выделенной строки:
      ' Visual Basic
      Static intRow As Integer
       
      // C#
      private int LastBoldedRow = 0;
      
    • Из свойства Application.ActiveCell берется ссылка на текущую ячейку:
      ' Visual Basic
      private int LastBoldedRow = 0;
      Dim rngCell As Excel.Range = ThisApplication.ActiveCell
       
      // C#
      Excel.Range rngCell = ThisApplication.ActiveCell;
      
    • Текущая строка выделяется полужирным с помощью свойства EntireRow активной ячейки:
      ' Visual Basic
      rngCell.EntireRow.Font.Bold = True
       
      // C#
      rngCell.EntireRow.Font.Bold = true;
      
    • Проверяется, что текущее значение intRow не равно 0 (это означает, что код выполняется первый раз):
      ' Visual Basic
      If intRow <> 0 Then
        ' Код опущен...
      End If
       
      // C#
      if (LastBoldedRow != 0)
      {
        // Код опущен...
      }
      
    • Проверяется, что текущая строка отличается от предыдущей. Состояние строки нужно менять, только если она не совпадает с предыдущей. Свойство Row возвращает целое значение, указывающее на строку, которая соответствует диапазону:
      ' Visual Basic
      If rngCell.Row <> intRow Then
        ' Код опущен...
      End If
       
      // C#
      if (rngCell.Row != LastBoldedRow)
      {
        // Код опущен...
      }
      
    • Берется ссылка на диапазон, содержащий ранее выделенную строку, и начертание шрифта этого диапазона меняется на обычное:
      ' Visual Basic
      Dim rng As Excel.Range = _
        DirectCast(ws.Rows(intRow), Excel.Range)
      rng.Font.Bold = False
       
      // C#
      Excel.Range rng = 
        (Excel.Range)ws.Rows[LastBoldedRow, Type.Missing];
      rng.Font.Bold = false;
      

    В примере рабочей книги процедура BoldCurrentRow вызывается в обработчике события SheetSelectionChange. В этом обработчике проверяется, что новое выделение принадлежит соответствующему диапазону (методом Intersect объекта Application) и, если да, вызывается процедура BoldCurrentRow:

    ' Visual Basic
    Private Sub ThisWorkbook_SheetSelectionChange( _
      ByVal Sh As Object, ByVal Target As Excel.Range) _
      Handles ThisWorkbook.SheetSelectionChange
     
      If Not ThisApplication.Intersect(Target, _
      ThisApplication.Range("BoldSelectedRow")) Is Nothing Then
        ' Выделение принадлежит диапазону, в котором выбранная строка
    
        ' помечается полужирным
        BoldCurrentRow(DirectCast(Sh, Excel.Worksheet))
      End If
    End Sub
     
    // C#
    protected void ThisWorkbook_SheetSelectionChange(
      System.Object sh, Excel.Range Target)
    {
      // Не забывайте, что метод Intersect принимает
      // 30 параметров
      if (ThisApplication.Intersect(Target, 
        ThisApplication.get_Range("BoldSelectedRow", Type.Missing), 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, 
        Type.Missing, Type.Missing, Type.Missing, Type.Missing) 
        != null)
      {
        // Выделение принадлежит диапазону, в котором выбранная строка
    
        // помечается полужирным
        BoldCurrentRow((Excel.Worksheet) sh);
      }
    }
    

    Работа с диапазонами

    Вы получили ссылку на диапазон, что с ней можно сделать? Как вы понимаете, список ответов на этот вопрос бесконечен. Здесь рассматривается несколько приемов работы с объектами Range и приводится соответствующий код (весь код доступен на листе Range Class рабочей книги примера).

    Автоматическое заполнение диапазонов

    Метод AutoFill класса Range позволяет автоматически заполнить диапазон значениями. Чаще всего метод AutoFill используется для занесения в диапазон последовательно возрастающих или убывающих значений. Поведение при автозаполнении задается необязательной константой из перечислимого XlAutoFillType (xlFillDays, xlFillFormats, xlFillSeries, xlFillWeekdays, xlGrowthTrend, xlFillCopy, xlFillDefault, xlFillMonths, xlFillValues, xlFillYears или xlLinearTrend). Если тип заполнения не указан, Excel использует тип заполнения по умолчанию (xlFillDefault) и заполняет заданный диапазон так, как считает нужным.

    В примере рабочего листа на рис. 24 имеются четыре автоматически заполняемых области. Столбец B должен содержать пять дней недели, столбец C - пять месяцев, столбец D - пять дат с годами по нарастающей, а столбец E - последовательность чисел, каждое из которых на 2 больше предыдущего. На рис. 25 показаны те же области после выполнения кода.

    Рис. 24. Четыре области до вызова метода AutoFill

    Рис. 25. Четыре области после автозаполнения

    По щелчку ссылки AutoFill выполняется следующая процедура:

    ' Visual Basic
    Private Sub AutoFill()
      Dim rng As Excel.Range = ThisApplication.Range("B1")
      rng.AutoFill(ThisApplication.Range("B1:B5"), _
      Excel.XlAutoFillType.xlFillDays)
     
      rng = ThisApplication.Range("C1")
      rng.AutoFill(ThisApplication.Range("C1:C5"), _
      Excel.XlAutoFillType.xlFillMonths)
     
      rng = ThisApplication.Range("D1")
      rng.AutoFill(ThisApplication.Range("D1:D5"), _
      Excel.XlAutoFillType.xlFillYears)
     
      rng = ThisApplication.Range("E1:E2")
      rng.AutoFill(ThisApplication.Range("E1:E5"), _
      Excel.XlAutoFillType.xlFillSeries)
    End Sub
     
    // C#
    private void AutoFill()
    {
      Excel.Range rng = ThisApplication.get_Range("B1", Type.Missing);
      rng.AutoFill(ThisApplication.get_Range("B1:B5", Type.Missing), 
        Excel.XlAutoFillType.xlFillDays);
     
      rng = ThisApplication.get_Range("C1", Type.Missing);
      rng.AutoFill(ThisApplication.get_Range("C1:C5", Type.Missing), 
        Excel.XlAutoFillType.xlFillMonths);
     
      rng = ThisApplication.get_Range("D1", Type.Missing);
      rng.AutoFill(ThisApplication.get_Range("D1:D5", Type.Missing), 
        Excel.XlAutoFillType.xlFillYears);
     
      rng = ThisApplication.get_Range("E1:E2", Type.Missing);
      rng.AutoFill(ThisApplication.get_Range("E1:E5", Type.Missing), 
        Excel.XlAutoFillType.xlFillSeries);
    }
    

    В каждом случае нужно указать два диапазона:

    • тот, для которого вызывается метод AutoFill (этот диапазон задает "начальную точку" заполнения);
    • заполняемый диапазон, передаваемый методу AutoFill в качестве параметра; этот диапазон должен включать исходный диапазон.

    Второй параметр метода AutoFill перечислимого типа XlAutoFillType является необязательным. Обычно он передается, чтобы задать требуемое поведение. Например, попробуйте изменить код:

    ' Visual Basic
    rng.AutoFill(ThisApplication.Range("D1:D5"), _
      Excel.XlAutoFillType.xlFillYears)
     
    // C#
    rng.AutoFill(ThisApplication.get_Range("D1:D5", Type.Missing), 
      Excel.XlAutoFillType.xlFillYears);
    

    на:

    ' Visual Basic
    rng.AutoFill(ThisApplication.Range("D1:D5"))
     
    // C#
    rng.AutoFill(ThisApplication.get_Range("D1:D5", Type.Missing), 
      Excel.XlAutoFillType.xlFillDefault);
    

    Тогда вместо дат, у которых возрастает год, будут формироваться даты, у которых возрастает день.

    Поиск в диапазонах

    Метод Find класса Range позволяет искать текст в диапазоне. Этот гибкий метод имитирует поведение диалогового окна Find and Replace (рис. 26). Фактически он напрямую взаимодействует с этим диалоговым окном. Таким образом, метод Range.Find или принимает параметры, которые вы указываете, чтобы задать поведение при поиске, или, если параметры не заданы, берет значения из диалогового окна Find and Replace. В табл. 4 перечислены параметры метода Range.Find; все параметры, кроме первого, необязательны.

    Рис. 26. Параметры, задаваемые в этом диалоговом окне, влияют на поведение метода Find

    Внимание На самом деле, поскольку почти все параметры Range.Find необязательны и поскольку пользователь может изменять параметры в диалоговом окне Find and Replace, методу Find лучше передавать все значения, если вам нужно учитывать пользовательские настройки. Конечно, перед разработчиками на C# эта проблема не стоит - они и так должны указывать все параметры при каждом вызове метода.

    Табл. 4. Параметры метода Range.Find

     

    Свойство Тип Описание
    What (обязательный) Object Данные, которые нужно найти; могут быть строкой или любым другим типом данных Excel
    After Range Диапазон, с которого начинается поиск (поиск в самой этой ячейке не выполняется); если не задать эту ячейку, поиск начинается с левого верхнего угла диапазона
    LookIn XlFindLookin (xlValue, xlComments, xlFormulas) Тип информации, которую нужно найти; эти значения нельзя объединять оператором Or
    LookAt XlLookAt (xlWhole, xlPart) Задает, должны ли ячейки полностью совпадать с искомыми данными или достаточно частичного совпадения
    SearchOrder XlSearchOrder (xlByRows, xlByColumns) Определяет порядок поиска. Значение xlByRows (по умолчанию) задает поиск по горизонтали, а затем по вертикали. Значение xlByColumns задает поиск по вертикали, а затем по горизонтали
    SearchDirection XlSearchDirection (xlNext, xlPrevious) Задает направление поиска; по умолчанию используется xlNext
    MatchCase Boolean Задает, учитывать ли регистр букв при поиске
    MatchByte Boolean Задает режим сравнения двухбайтовых символов: при значении True двухбайтовые символы всегда считаются несовпадающими с однобайтовыми, а при значении False двухбайтовые символы считаются совпадающими с эквивалентными однобайтовыми; применим, только если установлена поддержка двухбайтовых символов

    В следующем примере из нашей рабочей книги выполняется поиск в диапазоне (с именем Fruits) и изменяется шрифт ячеек, содержащих слово "apples" (результаты поиска даны на рис. 27). Кроме того, в этой процедуре используется метод FindNext, повторяющий поиск для заданного ранее набора параметров поиска. (Метод Range.FindPrevious работает почти так же, как и метод Range.FindNext, но в этом примере он не используется.) Вы задаете ячейку, с которой начинается поиск, а остальное делает метод FindNext.

    Рис. 27. Результаты поиска ячейки, содержащей слово "apples"

    Совет Метод FindNextFindPrevious) возвращается в начало диапазона поиска после того, как достигает конца диапазона. Вы должны проверять в своем коде, что метод не вернулся в начало, иначе приложение войдет в бесконечный цикл. В процедуре-примере показывается один из способов решения этой проблемы. Кроме того, если нужно избежать такого бесконечного возвращения в начало или выполнить поиск, слишком сложный для методов Find/FindNext/FindPrevious, можно перебирать все ячейки диапазона в цикле For Each.

    По щелчку ссылки Find на листе Range Class рабочей книги примера выполняется следующая процедура:

    ' Visual Basic
    Private Sub DemoFind()
      Dim rng As Excel.Range = ThisApplication.Range("Fruits")
      Dim rngFound As Excel.Range
     
      ' Запоминаем первую найденную ячейку
      Dim rngFoundFirst As Excel.Range
     
      ' Следует указывать все эти параметры при каждом вызове метода,
      ' так как они могут быть переопределены в UI
      rngFound = rng.Find( _
      "apples", , _
      Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart, _
      Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext, 
      False)
      While Not rngFound Is Nothing
        If rngFoundFirst Is Nothing Then
        rngFoundFirst = rngFound
        ElseIf rngFound.Address = rngFoundFirst.Address Then
        Exit While
        End If
        With rngFound.Font
        .Color = ColorTranslator.ToOle(Color.Red)
        .Bold = True
        End With
        rngFound = rng.FindNext(rngFound)
      End While
    End Sub
     
    // C#
    private void DemoFind()
    {
      Excel.Range rng = ThisApplication.
        get_Range("Fruits", Type.Missing);
      Excel.Range rngFound;
     
      // Запоминаем первую найденную ячейку
      Excel.Range rngFoundFirst = null;
     
      // Следует указывать все эти параметры при каждом вызове метода,
      // так как они могут быть переопределены в UI
      rngFound = rng.Find("apples", Type.Missing, 
        Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart, 
        Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext, 
        false, Type.Missing, Type.Missing);
      while (rngFound != null)
      {
        if (rngFoundFirst == null ) 
        {
        rngFoundFirst = rngFound;
        }
        else if (GetAddress(rngFound) == GetAddress(rngFoundFirst))
        {
        break;
        }
        rngFound.Font.Color = ColorTranslator.ToOle(Color.Red);
        rngFound.Font.Bold = true;
        rngFound = rng.FindNext(rngFound);
      }
    }
    

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

    • Объявляются переменные Excel.Range для хранения ссылок на весь диапазон, на первый найденный и на текущий найденный:
      ' Visual Basic
      Dim rng As Excel.Range = ThisApplication.Range("Fruits")
      Dim rngFound As Excel.Range
      Dim rngFoundFirst As Excel.Range
       
      // C#
      Excel.Range rng = ThisApplication.
        get_Range("Fruits", Type.Missing);
      Excel.Range rngFound;
      Excel.Range rngFoundFirst = null;
      
    • Выполняется поиск первого совпадения; указываются все параметры, кроме ячейки, с которой начинается поиск, - по умолчанию поиск начинается с левого верхнего угла диапазона. В значениях ячеек ищем строку "apples", допускаем частичные совпадения, поиск ведем по строкам в прямом направлении, без учета регистра букв:
      ' Visual Basic
      rngFound = rng.Find( _
        "apples", , _
        Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart, _
        Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext, _
        False)
       
      // C#
      rngFound = rng.Find("apples", Type.Missing, 
        Excel.XlFindLookIn.xlValues, Excel.XlLookAt.xlPart, 
        Excel.XlSearchOrder.xlByRows, Excel.XlSearchDirection.xlNext, 
        false, Type.Missing, Type.Missing);
      
    • Поиск продолжается, пока обнаруживаются совпадения:
      ' Visual Basic
      While Not rngFound Is Nothing
        ' Код опущен...
      End While
       
      // C#
      while (rngFound != null)
      {
        // Код опущен...
      }
      
    • Первый найденный диапазон (rngFoundFirst) сравнивается с Nothing; это условие выполняется, если только что обнаружено первое совпадение. Если это условие не выполняется, адрес найденного диапазона сравнивается с адресом первого найденного диапазона, и при совпадении адресов происходит выход из цикла.
      ' Visual Basic
      If rngFoundFirst Is Nothing Then
        rngFoundFirst = rngFound
      ElseIf rngFound.Address = rngFoundFirst.Address Then
        Exit While
      End If
       
      // C#
      if (rngFoundFirst == null ) 
      {
        rngFoundFirst = rngFound;
      }
      else if (GetAddress(rngFound) == GetAddress(rngFoundFirst))
      {
        break;
      }
      
    • Задается шрифт для диапазона с найденными значениями:
      ' Visual Basic
      With rngFound.Font
        .Color = ColorTranslator.ToOle(Color.Red)
        .Bold = True
      End With
       
      // C#
      rngFound.Font.Color = ColorTranslator.ToOle(Color.Red);
      rngFound.Font.Bold = true;
      
    • Выполняется поиск следующего значения:
      ' Visual Basic
      rngFound = rng.FindNext(rngFound)
       
      // C#
      rngFound = rng.FindNext(rngFound);
      

    По щелчку ссылки Reset Find на листе-примере выполняется простая процедура, возвращающая диапазон поиска в первоначальное состояние:

    ' Visual Basic
    Private Sub ResetFind()
      Dim rng As Excel.Range = ThisApplication.Range("Fruits")
      With rng.Font
        .Color = ColorTranslator.ToOle(Color.Black)
        .Bold = False
      End With
    End Sub
     
    // C#
    private void ResetFind()
    {
      Excel.Range rng = ThisApplication.
        get_Range("Fruits", Type.Missing);
      rng.Font.Color = ColorTranslator.ToOle(Color.Black);
      rng.Font.Bold = false;
    }
    

    Совет Если в диапазоне нужен поиск с заменой, вызывайте методом Range.Replace. Он во многом аналогичен методу Find, но позволяет указывать значение, на которое заменяются найденные значения. Метод Replace возвращает значение Boolean, сообщающее, выполнялись ли какие-либо замены. Если хотя бы одно значение было заменено, метод возвращает True.

    Сортировка данных в диапазоне

    Метод Range.Sort позволяет программно сортировать данные так же, как и в пользовательском интерфейсе Excel. Вы задаете диапазон, в котором выполняется сортировка, и при необходимости до трех строк или столбцов, по которым ведется сортировка, а также ряд необязательных параметров. Остальное делает Excel. В табл. 5 показаны все параметры метода Sort. (Разработчики на Visual Basic .NET скорее всего будут использовать лишь некоторые из них, а разработчикам на C# придется указывать значение каждого параметра.)

    Табл. 5. Параметры метода Sort

     

    Свойство Тип Описание
    Key1 Object (String или Range) Первое поле сортировки: или имя диапазона (String), или объект Range; задает, по каким значениям выполняется сортировка
    Order1 XlSortOrder (xlAscending, xlDescending) Порядок сортировки по полю, заданному параметром Key1
    Key2 Object (String или Range) Второе поле сортировки; этот параметр не используется при сортировке сводной таблицы
    Type Object Задает, какие элементы участвуют в сортировке сводной таблицы; при сортировке обычного диапазона ни на что не влияет
    Order2 XlSortOrder Порядок сортировки по полю, заданному параметром Key2
    Key3 Object (String или Range) Третье поле сортировки; этот параметр не используется при сортировке сводной таблицы
    Order3 XlSortOrder Устанавливает порядок сортировки по полю, заданному параметром Key3
    Header XlYesNoGuess (xlGuess, xlNo, xlYes) Задает, содержит ли первая строка заголовочную информацию; по умолчанию используется значение xlNo; если нужно, чтобы Excel определил это самостоятельно, укажите xlGuess
    OrderCustom Integer Задает нестандартный порядок сортировки; указывает индекс с отсчетом от 1 в списке нестандартных порядков сортировки; если вы опускаете этот параметр, используется порядок сортировки по умолчанию. На рис. 28 показано, как создать нестандартный порядок сортировки. В данном примере, чтобы выполнить сортировку в нестандартном порядке "fruits", нужно указать для этого параметра значение 6
    MatchCase Boolean True - сортировка с учетом регистра букв, False - без учета; для сводных таблиц не используется
    Orientation XlSortOrientation (xlSortRows, xlSortColumns) Ориентация сортировки
    SortMethod XlSortMethod (xlStroke, xlPinYin) Метод сортировки; применим не ко всем языкам (текущие значения применимы только к сортировке для китайского языка и не используются с другими языками)
    DataOption1 XlSortDataOption (xlSortTextAsNumbers, xlSortNormal) Указывает, как сортировать текст в диапазоне, заданном параметром Key1; не применяется при сортировке сводных таблиц
    DataOption2 XlSortDataOption Указывает, как сортировать текст в диапазоне, заданном параметром Key2; не применяется при сортировке сводных таблиц
    DataOption3 XlSortDataOption Указывает, как сортировать текст в диапазоне, заданном параметром Key3; не применяется при сортировке сводных таблиц

    Совет При вызове таких методов у разработчиков на Visual Basic .NET появляется явное преимущество перед разработчиками на C#. Поскольку вам вряд ли понадобятся все параметры, в Visual Basic .NET можно воспользоваться именованными параметрами, передавая лишь те, которые нужны. Разработчики на C#, чтобы принять значения по умолчанию, должны передавать пустые значения для всех неиспользуемых параметров.

    Рис. 28. Вы можете создавать нестандартные списки сортировки, а затем программно обращаться к ним

    По щелчку ссылки Sort на листе-примере Range Class выполняется процедура, сортирующая диапазон Fruits сначала по первому столбцу, затем по второму:

    ' Visual Basic
    Private Sub DemoSort()
      Dim rng As Excel.Range = ThisApplication.Range("Fruits")
      rng.Sort( _
      Key1:=rng.Columns(1), Order1:=Excel.XlSortOrder.xlAscending, _
      Key2:=rng.Columns(2), Order2:=Excel.XlSortOrder.xlAscending, _
      Orientation:=Excel.XlSortOrientation.xlSortColumns, _
      Header:=Excel.XlYesNoGuess.xlNo)
    End Sub
     
    // C#
    private void DemoSort()
    {
        Excel.Range rng = ThisApplication.
        get_Range("Fruits", Type.Missing);
     
        rng.Sort(rng.Columns[1, Type.Missing], 
        Excel.XlSortOrder.xlAscending, 
        rng.Columns[2, Type.Missing],Type.Missing, 
        Excel.XlSortOrder.xlAscending,
        Type.Missing, Excel.XlSortOrder.xlAscending,
        Excel.XlYesNoGuess.xlNo, Type.Missing, Type.Missing,
        Excel.XlSortOrientation.xlSortColumns, 
        Excel.XlSortMethod.xlPinYin,
        Excel.XlSortDataOption.xlSortNormal, 
        Excel.XlSortDataOption.xlSortNormal,
        Excel.XlSortDataOption.xlSortNormal);
    }
    

    По щелчку ссылки Reset Sort на том же листе выполняется процедура, выполняющая сортировку по второму полю в нестандартном порядке, показанном на рис. 28:

    ' Visual Basic
    Private Sub ResetSort()
      Dim rng As Excel.Range = ThisApplication.Range("Fruits")
      rng.Sort(rng.Columns(2), OrderCustom:=6, _
      Orientation:=Excel.XlSortOrientation.xlSortColumns, _
      Header:=Excel.XlYesNoGuess.xlNo)
    End Sub
     
    // C#
    private void ResetSort()
    {
      Excel.Range rng = ThisApplication.
        get_Range("Fruits", Type.Missing);
        rng.Sort(rng.Columns[2, Type.Missing],
        Excel.XlSortOrder.xlAscending, 
        Type.Missing, Type.Missing, Excel.XlSortOrder.xlAscending,
        Type.Missing, Excel.XlSortOrder.xlAscending,
        Excel.XlYesNoGuess.xlNo, 6, Type.Missing,
        Excel.XlSortOrientation.xlSortColumns, 
        Excel.XlSortMethod.xlPinYin,
        Excel.XlSortDataOption.xlSortNormal, 
        Excel.XlSortDataOption.xlSortNormal,
        Excel.XlSortDataOption.xlSortNormal);
    }
    

    Что дальше?

    Возможно, этот документ показался вам слишком длинным, но, прочитав его, вы сделали лишь первый шаг к освоению богатых возможностей объектной модели Excel. Вы познакомились с важнейшими классами - Application, Workbook, Worksheet и Range, - но в документе не описаны другие классы, которые могут оказаться полезными. Возможно, вам придется исследовать второй "уровень" классов объектной модели Excel, к которым относятся, например, PivotTable и Chart. Полнота объектной модели Excel позволяет решить почти любую задачу автоматизации - от вас требуется лишь желание найти нужный класс. Вооружившись знаниями, почерпнутыми из этого документа, Object Browser и справочной системой по Excel VBA, вы справитесь практически с любой задачей, которая может возникнуть при использовании Excel.


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


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

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

    Прислал: Demrak
    Спасибо за статью :) помогла :)

    Прислал: qwertmax
    Отличная статья!

    Прислал: файл-линк
    Спасибо за подробную статью

    Прислал: Андрей
    Большое спасибо, все доступно описано!

    Прислал: Vadim
    неплохой перевод https://msdn.microsoft.com/en-us/library/office/aa168292(v=office.11).aspx

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

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