?
Глава 2. Работа с Com сервером ExcelАннотация: В главе представлены собственные практические наработки автора по выводу информации из приложений, написанных в Visual Studio 2003/2005/2008 на C# в Excel. Все коды отлажены и неоднократно использовались. Вопросы, которые остались не затронуты, были до сих пор не востребованы в практической работе автора. Автор никому не давал права перепечатывать материал, но он 1:1 или кусками появляется на многих сайтах. Воровство в интернете к сожалению есть!
Введение. Решение и выбор способа связыванияПрежде чем приступить к рассмотрению поставленных вопросов, создадим новый простой проект (Рис.1.) с именем AppWordExcel (или любым другим). Поместим на панели приложения три контрола Button. Свойства Tag контролов установим, соответственно, в значения 1, 2 и 3. Выберем способ "раннего связывания" для сервера автоматизации Excel (см. Параграф 1. этого раздела). При написании кода будем использовать .Net сборки взаимодействия с приложениями Microsoft Office. Напомним, что при использовании импортирования библиотеки типов Com объекта и добавлении ссылки на него в Solutation Explorer (References, вкладка Com), нам сразу становится доступно пространство имен объекта (в данном случае Excel). При использовании .Net сборок взаимодействия с приложениями Microsoft Office нам, после добавления ссылки на Microsoft.Office.Interop.Excel (References, вкладка .Net), потребуется введение алиаса пространства имен Excel: using Excel = Microsoft.Office.Interop.Excel; Введение алиаса позволяет не только сократить количество кода при обращении к объектам, но и дает возможность использовать весь код, который мы напишем ниже, для любого способа
Рис.1. Проект решения AppWordExcel Создадим обработчик нажатия для кнопки 1 и замкнем на него обработчики нажатия всех кнопок. Запишем следующий, общий для всех примеров, приводимых ниже, код: private void button1_Click(object sender, EventArgs e) { int i = Convert.ToInt32(((Button)(sender)).Tag); switch(i) { case 1: break; case 2: break; default: Close(); break; } } В case 1 будем размещать код, в котором выполняется какое-либо действие по старту Excel и выводу информации, в case 2 - дополнительные действия и действия при закрытии приложения, в default - поместим код выхода из приложения. Параграф 1. Запуск и закрытие Excel из приложения на C#Объекты, которыми оперирует сервер Excel, несколько десятков. Мы будем рассматривать лишь основные, которые непосредственно требуются для обмена информацией приложения и сервера. Все объекты имеют иерархическую структуру. Сам сервер - объект Application или приложение Excel, может содержать одну или более книг, ссылки на которые содержит свойство Workbooks. Книги - объекты Workbook, могут содержать одну или более страниц, ссылки на которые содержит свойство Worksheets или (и) диаграмм - свойство Charts. Страницы - Worksheet, содержать объекты ячейки или группы ячеек, ссылки на которые становятся доступными через объект Range. Ниже в иерархии: строки, столбцы... Аналогично и для объекта Chart серии линий, легенды... Обратим внимание на то, что, интерфейс C# вместо понятия ячейки использует объекты Range (выбранная ячейка или группа ячеек). Отметим также группу объектов ActiveCell, ActiveChart и ActiveSheet, относящихся к активному окну (расположенному поверх других). Они, по набору свойств и методов, полностью аналогичны объектам Range, Chart и Sheet и, в ряде случаев, просто облегчают получение ссылки. Немного обособленно от этой иерархической структуры объектов находится свойство Windows объекта Excel.Application, предназначенное для управления окнами сервера Excel. Свойство Windows содержит набор объектов Window, которые имеют, в свою очередь, набор свойств и методов для управления размерами, видом, масштабом и упорядочиванием открытых окон, отображением заголовков, цветами и т.д. Эти же возможности доступны и для свойств и методов объекта Excel.Application - ActiveWindow (ссылка на активное окно). (Подробно об управлении окнами см. в параграфе "Некоторые возможности по управлению параметрами Excel"). Все эти объекты принято определять глобально для того, чтобы обеспечить доступ к ним из любой функции проекта. Определим глобально основной объект Excel.Application и, сразу, хотя он и понадобится нам значительно позже - объект Excel.Window: ..... using Excel = Microsoft.Office.Interop.Excel; using Word = Microsoft.Office.Interop.Word; namespace AppWordExcel { public partial class Form1 : Form { private Excel.Application excelapp; private Excel.Window excelWindow; public Form1() { InitializeComponent(); } Следующий код позволяет выполнять запуск Excel и его закрытие при нажатии соответственно кнопок 1 и 2. case 1: excelapp = new Excel.Application(); excelapp.Visible=true; break; case 2: excelapp.Quit(); break; default: Close(); break; Параграф 2. Создание рабочих книгВторым в иерархии объектов Excel.Application является объект Workbook. Информация об объектах Workbook хранится в виде ссылок на открытые рабочие книги в свойстве Workbooks. Книга в приложение может быть добавлена только через добавление ссылки в совокупность Workbooks, а ссылка на открытую книгу может быть получена различным образом (по имени, номеру, как ссылка на активную книгу). Рассмотрим создание двух рабочих книг из 3х и 5ти листов. case 1: excelapp = new Excel.Application(); excelapp.Visible=true; excelapp.SheetsInNewWorkbook=3; excelapp.Workbooks.Add(Type.Missing); excelapp.SheetsInNewWorkbook=5; excelapp.Workbooks.Add(Type.Missing); break; Свойство SheetsInNewWorkbook возвращает или устанавливает количество листов, автоматически помещаемых Excel в новые рабочие книги. В качестве параметра методу Add можно передать имя шаблона рабочей книги, однако, в этом случае мы привязываемся к пути, по которому инсталлированы приложения MicrosoftOffice. В примере использован другой способ: Type - класс декларации типов, Type.Missing - отсутствие значения. Некоторые методы Excel принимают необязательные параметры, которые не поддерживаются в C#. Для решения этой проблемы в коде на C# требуется передавать поле Type.Missing вместо каждого необязательного параметра, который является ссылочным типом (reference type). Кроме того, (этого нет в документации) при задании в методе ADD чисел от 1 до 7 будет создана книга с одним листом (1, 6), диаграмма(2), макрос (3, 4) и книга с четырьмя листами (5). Из других свойств отметим свойство TemplatesPath. С его помощью, зная имя файла шаблона, можно напрямую задавать имя шаблона (правда, в этом нет необходимости, если мы не хотим использовать, например, свой собственный шаблон). Свойство StartupPath возвращает путь к папке, которая содержит надстройки, выполняемые при запуске Excel и, хотя свойство для отображения информации нам ничего не дает, все же порой бывает необходимо найти имя файла настроек и удалить его для того, чтобы приложение работало только с собственными настройками. Книги могут быть не только добавлены, но и закрыты. Следующие вызовы закрывают все или конкретную рабочую книгу: excelapp.Workbooks.Close(); excelapp.Windows[1].Close(false, Type.Missing, Type.Missing); Остановимся более подробно на втором методе. Его параметры: expression.Close( SaveChanges, //Если в книге нет никаких изменений в документе, то параметр игнорируется. //Иначе, если есть изменения, но есть ссылки на закрываемую книгу //в других открытых окнах - этот параметр также игнорируется. //При отсутствии ссылок и наличии изменений - этот параметр //определяет, должны ли быть сохранены изменения. //При true и определенном параметре Filename - изменения //сохраняются, иначе запрашиваетcя имя файла. При false сохранения //нет. Если Type.Missing - вызывается диалоговое окно Save As. Filename, //Имя файла RouteWorkbook //Если файл не должен быть перенаправлен другому получателю //этот параметр игнорируется. Иначе при true файл направляется //следующему получателю. При false пересылки нет. ) Параграф 3. Сохранение документов3.1. Подготовка к сохранению документовДокументы Excel можно сохранить программно и обычным для Excel способом. В любом случае перед выходом из Excel необходимо вызвать метод Quit. Если свойство Excel.Application DisplayAlerts имеет значение true, Excel предложит сохранить несохраненные данные, если после старта в документ были внесены какие либо изменения. Excel автоматически не возвращает это свойство в значение по умолчанию, поэтому его рекомендуется возвращать в исходное состояние. Добавим в область глобального определения переменных еще две строчки, определив массив ссылок на созданные книги и на объект - конкретную книгу. private Excel.Workbooks excelappworkbooks; private Excel.Workbook excelappworkbook; Теперь, если выйти на конкретную книгу, как показано в примере, приведенном ниже, и присвоить свойству Saved объекта Workbook значение true, Excel согласно документации не должен предлагать сохранение независимо от того, были или нет изменения в данной книге (к сожалению, это не всегда работает). case 1: excelapp = new Excel.Application(); excelapp.Visible=true; excelapp.SheetsInNewWorkbook=3; excelapp.Workbooks.Add(Type.Missing); excelapp.SheetsInNewWorkbook=5; excelapp.Workbooks.Add(Type.Missing); //Запрашивать сохранение excelapp.DisplayAlerts=true; //Получаем набор ссылок на объекты Workbook (на созданные книги) excelappworkbooks=excelapp.Workbooks; //Получаем ссылку на книгу 1 - нумерация от 1 excelappworkbook=excelappworkbooks[1]; //Ссылку можно получить и так, но тогда надо знать имена книг, //причем, после сохранения - знать расширение файла //excelappworkbook=excelappworkbooks["Книга 1"]; //Запроса на сохранение для книги не должно быть excelappworkbook.Saved=true; //Используем свойство Count, число Workbook в Workbooks if(excelappworkbooks.Count > 1) { excelappworkbook=excelappworkbooks[2]; //Запрос на сохранение книги 2 должен быть excelappworkbook.Saved=false; } break; case 2: excelapp.Quit(); break; На некоторых вариациях версий Windows и Office запрос на сохранение может все равно присутствовать, хотя мы, и отключаем его в свойстве Saved. Из примера видно, что кроме Item, у набора Workbooks, как и у всех наборов в Microsoft Office, есть свойство Count, которое возвращает число элементов в наборе (в данном случае - объектов Workbook). Следующий вопрос, - в каком формате сохранять документ. Для получения формата открываемого документа и задания формата сохраняемого служит свойство Excel.Application DefaultSaveFormat. Свойство имеет много значений типа XlFileFormat (какие могут быть легко посмотреть в диалоговом окне "Сохранение документа" в поле "Тип файла", открыв Excel и выбрав пункт меню "Файл" | "Сохранить как"). Например, в case 1 допишем строчку: excelapp.DefaultSaveFormat=Excel.XlFileFormat.xlHtml; и в окне диалога сохранения файла будет установлен тип файла "Web страница". 3.2. Сохранение документаДля сохранения документов можно использовать методы Excel.Workbook Save и SaveAs. Метод Save сохраняет рабочую книгу в папке "Мои документы" с именами, присваиваемыми документу по умолчанию ("Книга1.xls", "Книга2.xls" ...) или в директорию и с именем под которым документ уже был сохранен. Изменим код в case 2, на следующий и продемонстрируем пример сохранения по умолчанию: case 2: //Устанавливаем формат excelapp.DefaultSaveFormat=Excel.XlFileFormat.xlExcel9795; //Будем спрашивать разрешение на запись поверх существующего документа excelapp.DisplayAlerts=true; excelappworkbook=excelappworkbooks[1]; //Сохраняем книгу 1 excelappworkbook.Save(); excelappworkbook=excelappworkbooks[2]; //Сохраняем книгу 2 excelappworkbook.Save(); excelapp.Quit(); break; При значении свойства DisplayAlerts=true Excel будет спрашивать - записать ли сохраняемый документ поверх существующего, при значении false - нет. Метод SaveAs позволяет сохранить документ с указанием имени, формата файла, пароля, режим доступа и т. д. Данный метод, как и метод Save, присваивает свойству Saved значение true. Метод SaveAs имеет следующий синтаксис: Workbook_object.SaveAs( Filename, //Имя сохраняемого файла FileFormat, //Формат сохраняемого файла Password, //Пароль доступа к файлу до 15 символов WriteResPassword, //Пароль на доступ на запись ReadOnlyRecommended, //При true режим только для чтения CreateBackup, //Создать резервную копию файла при true AccessMode, //Режим доступа к рабочей книге ConflictResolution, //Способ разрешения конфликтов AddToMru, //При true сохраненный документ добавляется //в список ранее открытых файлов TextCodePage, //Кодовая страница TextVisualLayout, //Направление размещения текста Local //Идентификатор ExcelApplication ) Для доступа к книге используются значение AccessMode xlShared - общая рабочая книга, xlExclusive - монопольный доступ или xlNoChange - запрет изменения режима доступа. Параметр ConflictResolution - способ разрешения конфликтов при одновременном внесении несколькими пользователями изменений в один документ - может иметь значения: xlUserResolution - отображение диалогового окна разрешения конфликтов (параметр по умолчанию), xlLocalSessionChanges - принятие изменений, внесенных пользователем или xlOtherSessionChanges - принятие изменений, внесенных другими пользователями. Следующий пример сохраняет открытые выше документы в формате .html и .xls, причем большинство параметров для первого документа передаются как не имеющие значения Type.Missing, для второго документа использовано паролирование и запрет изменения режима доступа (Excel.XlSaveAsAccessMode.xlNoChange): switch (i) { case 1: excelapp = new Excel.Application(); excelapp.Visible = true; excelapp.SheetsInNewWorkbook = 3; excelapp.Workbooks.Add(Type.Missing); excelapp.SheetsInNewWorkbook = 5; excelapp.Workbooks.Add(Type.Missing); excelappworkbooks = excelapp.Workbooks; break; case 2: try { excelappworkbook = excelappworkbooks[1]; excelappworkbook.Saved = true; excelapp.DisplayAlerts = false; excelapp.DefaultSaveFormat = Excel.XlFileFormat.xlHtml; excelappworkbook.SaveAs(@"C:\a.html", //object Filename Excel.XlFileFormat.xlHtml, //object FileFormat Type.Missing, //object Password Type.Missing, //object WriteResPassword Type.Missing, //object ReadOnlyRecommended Type.Missing, //object CreateBackup Excel.XlSaveAsAccessMode.xlNoChange,//XlSaveAsAccessMode AccessMode Type.Missing, //object ConflictResolution Type.Missing, //object AddToMru Type.Missing, //object TextCodepage Type.Missing, //object TextVisualLayout Type.Missing); //object Local excelappworkbook = excelappworkbooks["Book2"]; excelappworkbook.SaveAs(@"C:\a.xls", Excel.XlFileFormat.xlExcel9795, "WWWWW", //Пароль для доступа на запись "WWWWW", //Пароль для открытия документа Type.Missing, Type.Missing, Excel.XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); excelapp.Quit(); } catch (Exception ex) { //Обработка сбоя excelapp.Quit(); } }
Рис.2. Вызов документа с установленным паролем на доступ и запись Для сохранения документа может быть использован метод SaveCopyAs, который сохраняет копию рабочей книги в файле. Следующий пример, использующий метод SaveCopyAs полностью аналогичен примеру, использующему метод SaveAs при задании всех параметров как Type.Missing. case 2: excelapp.DefaultSaveFormat = Excel.XlFileFormat.xlHtml; excelappworkbook = excelappworkbooks[1]; excelappworkbook.Saved = true; excelappworkbook.SaveCopyAs(@"C:\a.html"); excelappworkbook = excelappworkbooks[2]; excelappworkbook.Saved = true; excelapp.DefaultSaveFormat = Excel.XlFileFormat.xlExcel9795; excelappworkbook.SaveCopyAs(@"C:\a.xls"); excelapp.Quit(); break; Метод SaveAs не производит преобразование документа и, поэтому, приведенный код вместо Web страницы a.html сохранит копию xls документа (изменит только расширение). Параграф 4. Открытие существующего документаДля открытия существующего документа основным методом является метод Open набора Excel.Workbooks. Для открытия текстовых файлов как рабочих книг, баз данных, файлов в формате .XML, используются методы OpenText, OpenDatabase или OpenXml. Об использовании методов OpenDatabase и OpenXml речь будет вестись в других темах. В данном параграфе рассмотрим метод Open. После выполнения предыдущего примера у нас осталось два рабочих файла a.html и a.xls, которые мы и откроем как две рабочие книги в Excel, изменив код в case 1: case 1: excelapp = new Excel.Application(); excelapp.Visible=true; excelapp.Workbooks.Open(@"C:\a.html", 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); excelapp.Workbooks.Open(@"C:\a.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); break; Метод Open имеет много параметров. Но, большинство из них, как видно из примера, необязательны. Рассмотрим параметры метода Open: Workbook_object.Open( FileName, //Имя открываемого файла файла UpdateLinks, //Способ обновления ссылок в файле ReadOnly, //При значении true открытие только для чтения Format, //Определение формата символа разделителя Password, //Пароль доступа к файлу до 15 символов WriteResPassword, //Пароль на сохранение файла IgnoreReadOnlyRecommended, //При значении true отключается вывод //запроса на работу без внесения изменений Origin, //Тип текстового файла Delimiter, //Разделитель при Format = 6 Editable, //Используется только для надстроек Excel 4.0 Notify, //При значении true имя файла добавляется в //список нотификации файлов Converter, //Используется для передачи индекса конвертера файла //используемого для открытия файла AddToMRU //При true имя файла добавляется в список //открытых файлов ) UpdateLinks - позволяет задать способ обновления ссылок в файле. Если данный параметр не задан, то выдается запрос на указание метода обновления. Значения: 0 - не обновлять ссылки; 1 - обновлять внешние ссылки; 2 - обновлять только удаленные ссылки; 3 - обновлять все ссылки. Format - при работе с текстовыми файлами определяет символ разделителя для полей, заносимых в различные ячейки документа. Значения параметра: 1 - символ табуляции; 2 - запятая; 3 - пробел; 4 - точка с запятой; 5 - нет разделителя; 6 - другой символ, определенный в параметре Delimiter. Приведем еще один пример - пример открытия текстового файла с использованием метода OpenText. Метод загружает в Excel текстовый файл как рабочую книгу с одиночным листом и производит его парсинг по ячейкам листа в соответствии с параметрами. Рассмотрим параметры метода OpenText: Workbook_object.OpenText( FileName, //Имя файла Origin, //Определяет происхождение текстового файла. //Может быть одна из XlPlatform: xlMacintosh, //xlWindows, или xlMSDOS. Может быть целое //число, определяющие номер кодовой страницы. //Если параметр опущен, то используется //текущая установка из Text Import Wizard Excel. StartRow, //Номер строки файла, с которой выполняется //преобразование. По умолчанию - 1. DataType, //Определяет формат столбца данных в файле и //есть разделения по столбцам или нет. //Может быть одна из следующих XlTextParsingType //констант: xlDelimited или xlFixedWidth. //Если этот параметр не определен, Microsoft Excel //пытается определять формат столбца при открытии. TextQualifier, //Текстовый спецификатор ограничителя строки //Может быть одна из XlTextQualifier констант: //XlTextQualifierDoubleQuote (двойная кавычка, по умолчанию), //XlTextQualifierSingleQuote (одинарная кавычка). //XlTextQualifierNone (нет ограничителя). ConsecutiveDelimiter, //При true последовательные разделители рассматриваются //как один разделитель. Значение по умолчанию false. Tab, //При true символ табуляции рассматривается как //разделитель (DataType должен быть xlDelimited). //Значение по умолчанию false. Semicolon, //Тоже, что и Tab для точки с запятой. Comma, //Тоже, что и Tab для запятой. Space, //Тоже, что и Tab для пробела. Other, //Если true, то OtherChar - свой символ разделителя. OtherChar, //Свой символ разделителя. FieldInfo, //Параметр типа xlColumnDataType. Массив двух элементных //массивов, содержащий информация для преобразования (для //каждого столбца). Первый элемент - номер столбца, //второй - формат: 1 - общий формат, 2 - текстовый, //3-8 даты, 9 - пропустить столбец. TextVisualLayout, //Направление размещение текста. DecimalSeparator, //Десятичный разделитель для чисел //Параметр по умолчанию - системная установка. ThousandsSeparator, //Разделитель тысяч при преобразовании чисел. //Параметр по умолчанию - системная установка. ) Влияние параметров DecimalSeparator и ThousandsSeparator на разбор чисел, представленных в текстовом формате, зависит от системных установок Windows и формата ячейки Excel. Следующая таблица показывает результаты импортирования текста в Excel для различных параметров настройки импорта (пример из MSDN).
Из таблицы видно, что для достижения требуемого вида числа необходимо будет после импорта текста изменить формат ячейки (числового формата в FieldInfo нет). Для демонстрации некоторых возможностей функции, создадим в любом текстовом редакторе простой текстовый файл "a.txt", в котором столбцы разделены символом табуляции - Tab (Рис.3).
Рис.3 Текстовый файл для импорта Выполним следующий код: case 1: excelapp = new Excel.Application(); excelapp.Visible=true; excelapp.Workbooks.OpenText( @"C:\a.txt", Excel.XlPlatform.xlWindows, 1, //С первой строки Excel.XlTextParsingType.xlDelimited, //Текст с разделителями Excel.XlTextQualifier.xlTextQualifierDoubleQuote, //Признак окончания разбора строки true, //Разделители одинарные true, //Разделители :Tab false, //Semicolon false, //Comma false, //Space false, //Other Type.Missing, //OtherChar new object[] {new object[]{1,Excel.xlColumnDataType.xlSkipColumn}, new object[]{2,Excel.xlColumnDataType.xlGeneralFormat}, new object[]{2,Excel.xlColumnDataType.xlMDYFormat}, new object[]{3,Excel.xlColumnDataType.xlMYDFormat}, new object[]{4,Excel.xlColumnDataType.xlTextFormat}, new object[]{5,Excel.xlColumnDataType.xlTextFormat}}, Type.Missing, //Размещение текста ".", //Разделитель десятичных разрядов ","); //Разделитель тысяч break: Результат выполнения фрагмента кода показан на Рис.4.
Рис.4. Импортированный текстовый файл С этим примером можно поэкспериментировать, меняя системные установки и заданные в программе разделители и меняя формат ячеек с числовой информацией. Параграф 5. Вывод информации в ячейки Excel5.1. Вывод без форматированияДля примеров данного параграфа будем использовать файл "C:\a.xls", созданный в предыдущем пункте. Вывод информации может быть выполнен на конкретный лист рабочей книги Excel в конкретную ячейку, поэтому нам необходимо определить объекты лист, в коллекции листов и ячейку. В глобальной области определения переменных напишем: private Excel.Sheets excelsheets; private Excel.Worksheet excelworksheet; Обратим внимание на разницу задания всех и рабочих листов книги. Аналогичного определения для ячеек и ячейки мы задать не можем, так как отдельно данные объекты как самостоятельные в C# отсутствуют, а есть понятие области выделенных ячеек, которая может включать одну или более ячеек, с которыми можно выполнять действия. Поэтому для ячеек, с которыми выполняется действие, введем следующее определение: private Excel.Range excelcells; Для выделения используется метод get_Range, который позволяет выделить группу ячеек через задание угловых ячеек диапазона, и есть возможность обратиться непосредственно к свойствам Rows и Cells - в любом случае выделенным будет диапазон ячеек. excelsheets=excelappworkbook.Worksheets; //Получаем ссылку на лист 1 excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Выделение группы ячеек excelcells=excelworksheet.get_Range("A1","С10"); //Тоже excelcells=excelworksheet.get_Range("A1","С10").Cells; excelcells=excelworksheet.get_Range("A1","С10").Rows; excelcells=excelworksheet.get_Range("A1","С10").Cells; //Одну ячейку excelcells=excelworksheet.get_Range("A1","A1"); excelcells=excelworksheet.get_Range("A1",Type.Missing); //Десять строк с 1 по 10ю excelcells=(Excel.Range)excelworksheet.Rows["1:10",Type.Missing]; //Три столбца excelcells=(Excel.Range)excelworksheet.Columns["A:C",Type.Missing]; //Одну строку excelcells=(Excel.Range)excelworksheet.Rows["1",Type.Missing]; //Один столбец excelcells=(Excel.Range)excelworksheet.Columns["C",Type.Missing]; Еще один способ определения выбранных ячеек - использование метода get_Offset(x,y) объекта Range, возвращающего объект Range, отстоящий от заданной ячейки на заданное количество строк и столбцов, считая от левого верхнего угла. Это позволяет работать с ячейками, позиция которых заданы относительно выбранной ячейки или группы ячеек. excelcells=excelworksheet.get_Range("A1",Type.Missing); .... выполняем действие с ячейкой A1 excelcells=excelcells.get_Offset(0,1); .... выполняем действие с ячейкой B1 excelcells=excelcells.get_Offset(1,-1); .... выполняем действие с ячейкой A2 Возможности объединения ячеек гораздо богаче - можно использовать объединения областей, группу областей, определение границ выделенных ячеек и.т.п., однако, для большинства практических задач вполне достаточно перечисленных выше методов. Выделенные ячейки далее могут быть объединены и с ними действия могут выполняться как с одной ячейкой. Для этого используется метод Merge: excelcells.Merge(Type.Missing); На данном этапе мы уже использовали основные объекты иерархической структуры объектов Excel. Следует также отметить и еще одну особенность группы свойств Excel.Application. Как только мы получили ссылку на конкретный объект (книгу, лист, группу ячеек, диаграмму) их можно сделать активными, применив к ним метод Activate(). С этого момента они доступны через соответствующие свойства ActiveWorkbook, ActiveSheet, ActiveChart, ActiveCell. Кроме того, при выполнении действий с конкретным объектом, он автоматически становится активным и, действия с ним могут далее выполняться с использованием перечисленных свойств. excelappworkbook=excelappworkbooks[1]; excelappworkbook.Activate(); excelsheets=excelapp.ActiveWorkbook.Worksheets; //Код аналогичен примеру использования метода get_Offset excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); excelcells= excelworksheet.get_Range("A1",Type.Missing); .... выполняем действие с ячейкой A1 excelcells=excelapp.ActiveCell.get_Offset(0,1); .... выполняем действие с ячейкой B1 excelcells=excelapp.ActiveCell.get_Offset(1,-1); .... выполняем действие с ячейкой A2 Точно также можно использовать и свойство Excel.Application Selection. То есть, объект может быть определен как селектированный и, далее, для ссылки на объект использоваться свойство Selection. В следующем примере объединяется группа ячеек в одну без ссылки на выделенный объект. excelcells=excelworksheet.get_Range("A1","C10"); excelcells.Select(); ((Excel.Range)(excelapp.Selection)).Merge(Type.Missing); Хотя это и заманчиво, чтобы работать с текущим селективным выбором как средством изменения свойств и поведения объекта, но лучше, все-таки, избегать этого. Причина - селективный выбор может быть легко изменен и во время выполнения приложения, например, кликом мышки в пределах документа, что при большом объеме вывода на 100% приведет к ошибке. Рассмотрим пример различных вариантов вывода в ячейки Excel, на различные страницы рабочей книги: private void button1_Click(object sender, EventArgs e) { int i = Convert.ToInt32(((Button)(sender)).Tag); { int i=Convert.ToInt32(e.Button.Tag); int m,n; switch(i) { case 1: excelapp = new Excel.Application(); excelapp.Visible=true; //Получаем набор ссылок на объекты Workbook excelappworkbooks=excelapp.Workbooks; //Открываем книгу и получаем на нее ссылку excelappworkbook=excelapp.Workbooks.Open(@"C:\a.xls", Type.Missing, Type.Missing, Type.Missing, "WWWWW","WWWWW", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); //Если бы мы открыли несколько книг, то получили ссылку так //excelappworkbook=excelappworkbooks[1]; //Получаем массив ссылок на листы выбранной книги excelsheets=excelappworkbook.Worksheets; //Получаем ссылку на лист 1 excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Выбираем ячейку для вывода A1 excelcells=excelworksheet.get_Range("A1","A1"); //Выводим число excelcells.Value2=10.5; //Выбираем лист 2 excelworksheet=(Excel.Worksheet)excelsheets.get_Item(2); //При выборе одной ячейки можно не указывать вторую границу excelcells=excelworksheet.get_Range("A1",Type.Missing); //Выводим значение текстовую строку excelcells.Value2="Лист 2"; excelcells.Font.Size=20; excelcells.Font.Italic=true; excelcells.Font.Bold=true; //Выбираем лист 3 excelworksheet=(Excel.Worksheet)excelsheets.get_Item(3); //Делаем третий лист активным excelworksheet.Activate(); //Вывод в ячейки используя номер строки и столбца Cells[строка, столбец] for(m=1; m < 20; m++) { for(n=1; n < 15; n++) { excelcells = (Excel.Range)excelworksheet.Cells[m,n]; //Выводим координаты ячеек excelcells.Value2=m.ToString()+" "+n.ToString(); } } break; case 2: //Сохраняем результат excelappworkbooks=excelapp.Workbooks; excelappworkbook=excelappworkbooks[1]; excelappworkbook.Save(); excelapp.Quit(); break; default: Close(); break; } }
Рис.5. Результаты выполнения фрагмента кода Результаты выполнения фрагмента кода показаны на Рис.5. Заметим, что в C# требуется считывать и присваивать значения свойству Value2, а не Value объекта Range, так как свойство Value содержит параметр. C# не поддерживает свойства с параметрами (за исключением индексных свойств). Если в приведенном выше примере для вывода на лист 1 выбрать не одну, а сразу несколько ячеек, то результат можно видеть на Рис.5.1. (фрагмент слева). excelcells=excelworksheet.get_Range("A1","C5"); Однако, как и в приложении Excel, можно объединить ячейки программно, задать выравнивание и получить результат, как на Рис.5.1 (вторай слева фрагмент). excelcells=excelworksheet.get_Range("A1","C5"); //Объединяем ячейки excelcells.Merge(Type.Missing); //Задаем выравнивание по центру excelcells.HorizontalAlignment=Excel.Constants.xlCenter; excelcells.VerticalAlignment=Excel.Constants.xlCenter; //Выводим число excelcells.Value2=10.5;
Рис. 5.1 Результаты выполнения примера c объединением ячеек 5.2. Форматированный выводПри выводе информации часто бывает необходимо изменить формат ячейки, например, задать числовой формат, это можно сделать следующим образом: //Очищаем содержимое ячейки и формат excelcells.Clear(); //Задаем формат excelcells.NumberFormat="### ##0,00"; //Выводим значение, которое будет отформатировано excelcells.Value2=100000.5; Результат будет зависеть от системных установок Windows (Пуск|Настройка|Панель управления|Язык и стандарты) и, для данного примера, результат может быть как на Рис.5.1. (третий слева фрагмент). Для формата даты и установки общего формата: excelcells.Clear(); excelcells.NumberFormat="Д ММММ, ГГГГ"; excelcells.Value2="01.11.2004 - 14.07.2007г."; Результат выполнения Рис.5.1. (фрагмент справа). И последнее - возврат к общему формату. excelcells.Clear(); excelcells.NumberFormat="Общий"; Приведенный ниже пример форматирования текста в ячейках добавлен в качестве ответа на вопрос, поступивший автору 20.01.2009г. Попробуем выполнить форматирование, показанное на Рис.6.
Рис.6. Пример форматированного вывода Макрос, реализующий данное форматирование, имеет вид: Sub Макрос1() ' Макрос1 Макрос ' Макрос записан 20.01.2009 (wlad) ActiveCell.FormulaR1C1 = "И это все можно" With ActiveCell.Characters(Start:=1, Length:=5).Font .Name = "Times New Roman" .FontStyle = "обычный" .Size = 24 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleNone .ColorIndex = 4 End With With ActiveCell.Characters(Start:=6, Length:=10).Font .Name = "Times New Roman" .FontStyle = "полужирный" .Size = 12 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleNone .ColorIndex = xlAutomatic End With Range("B1:B2").Select Range("B2").Activate Columns("A:A").ColumnWidth = 30.5 Range("A2").Select End Sub Его перевод на C#, будет выглядеть примерно так: //Эта функция выводит в ячейку A1 текст "И это все можно" //Вывод данных мы рассмотрели выше if(iOutputExcel(0,1,"И это все можно") == 1) return; //Делаем все содержимое ячейки жирным - пример форматирования данных во всей ячейки excelcells.EntireRow.Font.Bold = true; //Объект rng соответствует содержимому ячейки Range rng = excelapp.ActiveCell; object start=1; object end=5; //Выполняем форматирование фрагментов текста rng.get_Characters(start, end).Font.Bold = false; rng.get_Characters(start, end).Font.Italic = false; rng.get_Characters(start, end).Font.Size = 24; rng.get_Characters(start, end).Font.ColorIndex = 4; ........ 5.3. Вставка формулprivate string[] vsS ={ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE" }; ......... //Вызов формулы суммирующей A3:A9 в A10 iOutputExcelF(0, 10, 0, 3, 0, 9, "СУММ"); .......... #region iOutputExcelF private int iOutputExcelF(int a, int b, int c, int d, int e, int f, string sValue) { //a b - там где формула //с d - начало диапазона где цифры //e f - конец диапазона где цифры //Формула sValue excelcells = excelworksheet.get_Range(vsS[a] + Convert.ToString(b), Type.Missing); excelcells.Select(); excelcells.Formula = "="+sValue+"("+vsS[c] + Convert.ToString(d)+":"+vsS[e] + Convert.ToString(f)+")"; return 0; } #endregion Параграф 6. Защита листа и книги документа ExcelМатериал прислан Андреем Ковалевым и отредактирован автором. Для защиты листа документа или книги Excel необходимо установить пароль. В качестве пароля используется любая переменная тира string. Защищаем книгу: string s="andrey"; excelappworkbook.Protect(s, true, false); Пароль задавать необязательно - string s=string.Emptu; однако, если не задать пароль, любой пользователь сможет снять защиту с листа и изменить защищенные элементы. Второй параметр: true, означает защиту структуры (запрет перемещения, удаления, скрытия, показа или переименования, а также вставки новых листов). Третий параметр: true, означает защиту окна (блокировка окна для восстановления размера и расположения при каждом открытии книги). Соответственно для снятия защиты книги используем: string s="andrey"; excelappworkbook.Unprotect(s); Защищаем листы: string s="andrey"; foreach (Excel.Worksheet sheet in excelappworkbook.Worksheets) { sheet.Protect(s, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false); } Функция Protect определена в Microsoft.Office.Interop.Excel.dll как: void Protect(object Password, object DrawingObjects, object Contents, object Scenarios, object UserInterfaceOnly, object AllowFormattingCells, object AllowFormattingColumns, object AllowFormattingRows, object AllowInsertingColumns, object AllowInsertingRows, object AllowInsertingHyperlinks, object AllowDeletingColumns, object AllowDeletingRows, object AllowSorting, object AllowFiltering, object AllowUsingPivotTables); Множество параметров функции, начиная со второго, означают:
Для снятия защиты используем: string s="andrey"; foreach (Excel.Worksheet sheet in excelappworkbook.Worksheets) { sheet.Unprotect(s); } Параграф 7. Чтение информации из ячеек ExcelЧтение информации из ячеек Excel во многом аналогично выводу (см. выше). На выбранном листе необходимо в выбранной книге выбрать одну ячейку или объединенную группу ячеек (метод get_Range или преобразование к Excel.Range)- после чего достаточно преобразовать значения в выделенных ячейках к нужному типу данных. Создадим в Excel новую книгу, на первом листе запишем соответственно: Ячейка Что записано A1 В ячейке A2 число A2 5 A3 В ячейке A4 число A3 10,5 Сохраним документ с именем a1.xls в корне диска C. Запишем и выполним следующий код: private void button1_Click(object sender, EventArgs e) { int i = Convert.ToInt32(((Button)(sender)).Tag); int viRez; float vfRez; string sStr; switch(i) { case 1: excelapp = new Excel.Application(); excelapp.Visible=true; excelappworkbooks=excelapp.Workbooks; //Открываем книгу и получаем на нее ссылку excelappworkbook=excelapp.Workbooks.Open(@"C:\a1.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); excelsheets=excelappworkbook.Worksheets; //Получаем ссылку на лист 1 excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Выбираем ячейку для вывода A1 excelcells=excelworksheet.get_Range("A1",Type.Missing); sStr=Convert.ToString(excelcells.Value2); Text=sStr+" "; excelcells=excelworksheet.get_Range("A2",Type.Missing); viRez = Convert.ToInt32(excelcells.Value2); Text+=Convert.ToString(viRez)+" "; excelcells=excelworksheet.get_Range("A3",Type.Missing); sStr=Convert.ToString(excelcells.Value2); Text+=sStr+" "; excelcells=excelworksheet.get_Range("A4",Type.Missing); vfRez = Convert.ToSingle(excelcells.Value2); Text+=Convert.ToString(vfRez)+" "; break; ........ Код не требует пояснений - в заглавии приложения после выполнения будет выведено: В ячейке A2 число 5 В ячейке A4 число 10,5 Параграф 8. Рисуем табличкиЧтобы нарисовать табличку в Excel надо научиться рисовать рамки вокруг выбранной ячейки или объединенной группы ячеек. Шаги рисования рамки будут следующие:
Можно рисовать линии по любой границе ячейки и не по границе ячейки, для чего необходима задать расположение линии - вместо excelcells.Borders задать excelcells.Borders[направление], где направление может быть одним из следующих: Excel.XlBordersIndex.xlDiagonalDown, Excel.XlBordersIndex.xlDiagonalxlDiagonalUp, Excel.XlBordersIndex.xlDiagonalUp, Excel.XlBordersIndex.xlEdgeBottom, Excel.XlBordersIndex.xlEdgeLeft, Excel.XlBordersIndex.xlEdgeRight, Excel.XlBordersIndex.xlEdgeTop, Excel.XlBordersIndex.xlInsideHorizontal, Excel.XlBordersIndex.xlInsideVertical. Следующий пример демонстрирует выполнение обводки вокруг ячеек (Рис.7. слева), и, тем самым, при использовании для некоторой группы объединенных ячеек, показывает принцип рисования табличек. case 1: excelapp = new Excel.Application(); excelapp.Visible=true; //Получаем набор объектов Workbook (массив ссылок на созданные книги) excelappworkbooks=excelapp.Workbooks; //Открываем книгу и получаем на нее ссылку excelappworkbook=excelapp.Workbooks.Open(@"C:\a.xls", Type.Missing, Type.Missing, Type.Missing, "WWWWW","WWWWW", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); //Если бы мы открыли несколько книг, то получили ссылку так //excelappworkbook=excelappworkbooks[1]; //Получаем массив ссылок на листы выбранной книги excelsheets=excelappworkbook.Worksheets; //Получаем ссылку на лист 1 excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Выбираем ячейку для вывода excelcells=excelworksheet.get_Range("B2","C5"); //Объединяем ячейки excelcells.Merge(Type.Missing); //Устанавливаем цвет обводки excelcells.Borders.ColorIndex=3; //Устанавливаем стиль и толщину линии excelcells.Borders.LineStyle=Excel.XlLineStyle.xlContinuous; excelcells.Borders.Weight=Excel.XlBorderWeight.xlThick; break;
Рис.7. Создание рамок вокруг ячеек и выполнение заливки Добавим две строчки к коду предыдущего примера и можем выполнить заливку ячеек (Рис.7. справа). excelcells.Interior.ColorIndex=34; excelcells.Interior.PatternColorIndex=Excel.Constants.xlAutomatic; Параграф 9. Создание диаграммДля того, чтобы создать диаграмму, она должна быть привязана к конкретным ячейкам с цифровой информацией, поэтому откроем наш файл C:\a.xls и нарисуем в нем табличку, показанную на Рис.8. (у кого есть время - может выполнить это программно - в предыдущих параграфах есть достаточно материала, чтобы сделать это).
Рис.8. Табличка для диаграммы 8.1. Пошаговое создание диаграммПриведенный ниже пример может показаться громоздким, и не всегда нужно будет пройти все шаги, которые требуются для создания диаграмм, и, конечно, всегда может потребоваться еще что-то в смысле дополнительных усовершенствований стилей, надписей и т.п. Однако в примере есть все, чтобы сразу, напрямую используя приведенные ниже коды, можно было использовать в приложении связанные с таблицами диаграммы. Путь создания тоже не бесспорный и ниже приведен еще один пример, как можно вставить диаграмму на лист Excel, но отличие обоих путей не существенны, а после того как диаграмма вставлена, путь ее изменения может быть только таким, как показано в этом примере. Некоторые общие замечания по коду:
Код испытан в решении, описанном в начале раздела. Как тип диаграммы можно задать один из предопределенных: xlArea, xlBar, xlColumn, xlLine, xlPie, xlRadar, xlXYScatter, xlCombination, xl3DArea, xl3DBar, xl3DColumn, xl3DLine, xl3DPie, xl3DSurface, xlDoughnut, xlDefaultAutoFormat. private void button1_Click(object sender, EventArgs e) { int i = Convert.ToInt32(((Button)(sender)).Tag); switch(i) { case 1: excelapp = new Excel.Application(); excelapp.Visible=true; //Получаем набор объектов Workbook (массив ссылок на созданные книги) excelappworkbooks=excelapp.Workbooks; //Открываем книгу и получаем на нее ссылку //Помним, что файл был запаралирован excelappworkbook=excelapp.Workbooks.Open(@"C:\a.xls",Type.Missing, Type.Missing, Type.Missing, "WWWWW","WWWWW", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); //Если бы мы открыли несколько книг, то получили ссылку так //excelappworkbook=excelappworkbooks[1]; //Получаем массив ссылок на листы выбранной книги excelsheets=excelappworkbook.Worksheets; //Получаем ссылку на лист 1 excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Выделяем ячейки с данными в таблице excelcells=excelworksheet.get_Range("D8","K10"); //И выбираем их excelcells.Select(); //Создаем объект Excel.Chart диаграмму по умолчанию Excel.Chart excelchart=(Excel.Chart)excelapp.Charts.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing); //Выбираем диграмму - отображаем лист с диаграммой excelchart.Activate(); excelchart.Select(Type.Missing); //Изменяем тип диаграммы excelapp.ActiveChart.ChartType =Excel.XlChartType.xlConeCol; //Создаем надпись - Заглавие диаграммы excelapp.ActiveChart.HasTitle=true; excelapp.ActiveChart.ChartTitle.Text ="Продажи фирмы Рога и Копыта за неделю"; //Меняем шрифт, можно поменять и другие параметры шрифта excelapp.ActiveChart.ChartTitle.Font.Size = 14; excelapp.ActiveChart.ChartTitle.Font.Color=255; //Обрамление для надписи c тенями excelapp.ActiveChart.ChartTitle.Shadow = true; excelapp.ActiveChart.ChartTitle.Border.LineStyle = Excel.Constants.xlSolid; //Даем названия осей ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).HasTitle = true; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).AxisTitle.Text = "День недели"; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlSeriesAxis, Excel.XlAxisGroup.xlPrimary)).HasTitle = false; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).HasTitle = true; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).AxisTitle.Text = "Рогов/Копыт"; //Координатная сетка - оставляем только крупную сетку ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).HasMajorGridlines = true; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).HasMinorGridlines = false; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlSeriesAxis, Excel.XlAxisGroup.xlPrimary)).HasMajorGridlines = true; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlSeriesAxis, Excel.XlAxisGroup.xlPrimary)).HasMinorGridlines = false; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).HasMinorGridlines=false; ((Excel.Axis)excelapp.ActiveChart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).HasMajorGridlines=true; //Будем отображать легенду и уберем строки, //которые отображают пустые строки таблицы excelapp.ActiveChart.HasLegend = true; //Расположение легенды excelapp.ActiveChart.Legend.Position = Excel.XlLegendPosition.xlLegendPositionLeft; //Можно изменить шрифт легенды и другие параметры ((Excel.LegendEntry)excelapp.ActiveChart.Legend.LegendEntries(1)).Font.Size=12; ((Excel.LegendEntry)excelapp.ActiveChart.Legend.LegendEntries(3)).Font.Size=12; //Легенда тесно связана с подписями на осях - изменяем надписи // - меняем легенду, удаляем чтото на оси - изменяется легенда Excel.SeriesCollection seriesCollection= (Excel.SeriesCollection)excelapp.ActiveChart.SeriesCollection(Type.Missing); Excel.Series series = seriesCollection.Item(1); series.Name="Рога"; //Помним, что у нас объединенные ячейки, значит каждая второя строка - пустая //Удаляем их из диаграммы и из легенды series = seriesCollection.Item(2); series.Delete(); //После удаления второго (пустого набора значений) третий занял его место series = seriesCollection.Item(2); series.Name="Копыта"; series = seriesCollection.Item(3); series.Delete(); series = seriesCollection.Item(1); //Переименуем ось X series.XValues= "Понедельник;Вторник;Среда;Четверг;Пятница;Суббота;Воскресенье;Итог"; //Если закончить код на этом месте то у нас Диаграммы на отдельном листе - Рис.9. //Строку легенды можно удалить здесь, но строка на оси не изменится //Поэтому мы удаляли в Excel.Series //((Excel.LegendEntry)excelapp.ActiveChart.Legend.LegendEntries(2)).Delete(); //Перемещаем диаграмму на лист 1 excelapp.ActiveChart.Location(Excel.XlChartLocation.xlLocationAsObject,"Лист1"); //Получаем ссылку на лист 1 excelsheets=excelappworkbook.Worksheets; excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Перемещаем диаграмму в нужное место excelworksheet.Shapes.Item(1).IncrementLeft(-201); excelworksheet.Shapes.Item(1).IncrementTop((float)20.5); //Задаем размеры диаграммы excelworksheet.Shapes.Item(1).Height=550; excelworksheet.Shapes.Item(1).Width=500; //Конец кода - диаграммы на листе там где и таблица break; case 2: excelappworkbooks=excelapp.Workbooks; excelappworkbook=excelappworkbooks[1]; excelappworkbook.Save(); excelapp.Quit(); break; default: Close(); break; }
Рис.9. Диаграммы на отдельном листе
Рис.10. Диаграммы на листе 1 Есть возможность поместить диаграмму сразу на выбранном листе. Но, в этом случае, нельзя использовать метод ActiveChart и, поэтому, предыдущий код незначительно изменится. В примере комментарии даны в строках, имеющих принципиальное отличие от кода предыдущего примера. case 1: excelapp = new Excel.Application(); excelapp.Visible=true; excelappworkbooks=excelapp.Workbooks; excelappworkbook=excelapp.Workbooks.Open(@"C:\a.xls",Type.Missing, Type.Missing, Type.Missing, "WWWWW","WWWWW", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); excelsheets=excelappworkbook.Worksheets; excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Определяем диаграммы как объекты Excel.ChartObjects Excel.ChartObjects chartsobjrcts = (Excel.ChartObjects)excelworksheet.ChartObjects(Type.Missing); //Добавляем одну диаграмму в Excel.ChartObjects - диаграмма пока //не выбрана, но место для нее выделено в методе Add Excel.ChartObject chartsobjrct = chartsobjrcts.Add(10,200,500,400); excelcells=excelworksheet.get_Range("D8","K10"); //Получаем ссылку на созданную диаграмму Excel.Chart excelchart=chartsobjrct.Chart; //Устанавливаем источник данных для диаграммы excelchart.SetSourceData(excelcells,Type.Missing); //Далее отличия нет excelchart.ChartType=Excel.XlChartType.xlConeCol; excelchart.HasTitle=true; excelchart.ChartTitle.Text="Продажи фирмы Рога и Копыта за неделю"; excelchart.ChartTitle.Font.Size = 14; excelchart.ChartTitle.Font.Color=255; excelchart.ChartTitle.Shadow = true; excelchart.ChartTitle.Border.LineStyle = Excel.Constants.xlSolid; ((Excel.Axis)(excelchart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary))) .HasTitle =true; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).HasTitle =true; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).AxisTitle.Text = "День недели"; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlSeriesAxis, Excel.XlAxisGroup.xlPrimary)).HasTitle = false; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).HasTitle = true; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).AxisTitle.Text = "Рогов/Копыт"; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).HasMajorGridlines = true; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlCategory, Excel.XlAxisGroup.xlPrimary)).HasMinorGridlines = false; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlSeriesAxis, Excel.XlAxisGroup.xlPrimary)).HasMajorGridlines = true; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlSeriesAxis, Excel.XlAxisGroup.xlPrimary)).HasMinorGridlines = false; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).HasMinorGridlines=false; ((Excel.Axis)excelchart.Axes(Excel.XlAxisType.xlValue, Excel.XlAxisGroup.xlPrimary)).HasMajorGridlines=true; excelchart.HasLegend = true; excelchart.Legend.Position = Excel.XlLegendPosition.xlLegendPositionLeft; ((Excel.LegendEntry)excelchart.Legend.LegendEntries(1)).Font.Size=12; ((Excel.LegendEntry)excelchart.Legend.LegendEntries(3)).Font.Size=12; Excel.SeriesCollection seriesCollection= (Excel.SeriesCollection)excelchart.SeriesCollection(Type.Missing); Excel.Series series = seriesCollection.Item(1); series.Name="Рога"; series = seriesCollection.Item(2); series.Delete(); series = seriesCollection.Item(2); series.Name="Копыта"; series = seriesCollection.Item(1); series.XValues= "Понедельник;Вторник;Среда;Четверг;Пятница;Суббота;Воскресенье;Итог"; break; Код формирует туже диаграмму (Рис.10.), что и предыдущий пример. 9.2. Использование метода ChartWizard для создания диаграммМетод свойства Chart объекта типа ChartsObject имеет достаточно много параметров, большинство из которых, как всегда, могут не указываться (Type.Missing), однако чем больше их будет указано - тем меньше далее потребуется писать кода, аналогичного коду предыдущего примера. Поэтому рассмотрим параметры метода: ChartWizard( object Source, //Диапазон исходных данных для новой диаграммы. //Если параметр опущен, редактируется выбранная //диаграмма на активном рабочем листе. object Gallery, //Тип диаграммы - возможные значения см. выше object Format, //Номер опции (1 до 10) для встроенных автоформатов. //Если этот параметр опущен, выбирается значение по //умолчанию для типа галереи и источника данных. //Подобрать можно только экспериментально //(для xl3DArea например от 1 до 8, а 9 - exception object PlotBy, //Определяет, находятся ли данные для каждого ряда //в строках или столбцах, обычно Excel.XlRowCol.xlRows object CategoryLabels, //Число отображаемых строк или столбцов (в зави- //симости от значения PlotBy и на 1 меньше //максимально заданного в источнике данных) - //параметр лучше оставить 0 или Type.Missing если //не надо уменьшить значение object SeriesLabels, //Тоже, что и CategoryLabels для значений Object HasLegend, //При true отображать легенду object Title, //Заглавие диаграммы object CategoryTitle, //Текст заголовка оси категории object ValueTitle, //Текст заголовка оси значения object ExtraTitle //Текст Заголовка 3 оси для 3х мерных диаграмм ); Немного изменим код предыдущего примера для построения диаграммы с использованием ChartWizard. case 1: excelapp = new Excel.Application(); excelapp.Visible=true; excelappworkbooks=excelapp.Workbooks; excelappworkbook=excelapp.Workbooks.Open(@"C:\a.xls",Type.Missing, Type.Missing, Type.Missing, "WWWWW","WWWWW", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing); excelsheets=excelappworkbook.Worksheets; excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); excelworksheet.Activate(); Excel.ChartObjects chartsobjrcts = (Excel.ChartObjects)excelworksheet.ChartObjects(Type.Missing); Excel.ChartObject chartsobjrct = chartsobjrcts.Add(10,200,500,400); chartsobjrct.Chart.ChartWizard(excelworksheet.get_Range("D8","K10"), Excel.XlChartType.xl3DArea,2,Excel.XlRowCol.xlRows,Type.Missing, 0,true,"Продажа рогов и копыт за неделю","Дни недели","Рога\\Копыта",Type.Missing); break;
Рис.11. Диаграмма, построенная с использованием ChartWizard Код может показаться проще, но как видно из Рис.11., метод реализует далеко не все возможности и вновь придется вернуться к методам, которые мы использовали выше. Параграф 10. Обработка событий сервера ExcelСобытия также необходимы для создания функционального приложения для работы с Excel как и доступ к свойствам и методам. Если рассматривать использование свойств и методов, предоставляемых интерфейсом COM объекта, как прямую связь по управлению сервером, то события обеспечивают обратную связь. Благодаря наличию событий, приложение может обеспечить программную функциональность для отклика на происходящее в приложении. Объекты Excel, также как и любой контрол C#, имеют свои события и программист, как и для контрола, может создать обработчик для любого из событий. Однако, у нас нет визуального компонента Excel и нельзя двойным кликом мышки в окошечке напротив события в окне Properties на вкладке Events создать обработчик. Можно попробовать сделать это вручную. Вспомним, как мы это делали, например, в параграфе "Присоединение меню для формы" в первом разделе. Но, при этом, возникает вопрос - где взять передаваемые в приложения параметры событий? И сами события, и параметры есть в проекте решения, а изложенное ниже - методика создания обработчика событий для серверов автоматизации. Для создания обработчика событий необходимо:
Это все шаги, которые необходимо сделать для добавления событий. Следующий пример показывает как, меняя лист в книге Excel или вводя информацию в ячейку (не важно, программно или вручную), мы выводим информацию об этом в приложение, а закрывая книгу - уничтожаем объект Excel.Application, что позволяет избежать зависших процессов Excel в Windows (по крайней мере после закрытия приложения все процессы уничтожаются): using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; //using System.Reflection; //using System.Diagnostics; using Excel = Microsoft.Office.Interop.Excel; using Word = Microsoft.Office.Interop.Excel; namespace AppWordExcel { public partial class Form1 : Form { Excel.WorkbookEvents_SheetActivateEventHandler sheet_Activate = null; Excel.WorkbookEvents_SheetChangeEventHandler book_SheetChange = null; Excel.WorkbookEvents_BeforeCloseEventHandler before_bookClose = null; private Excel.Application excelapp; //private Excel.Window excelWindow; //private Excel.Workbooks excelappworkbooks; private Excel.Workbook excelappworkbook; private Excel.Sheets excelsheets; private Excel.Worksheet excelworksheet; private bool fExit = false; //private Excel.Range excelcells; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { int i = Convert.ToInt32(((System.Windows.Forms.Button)(sender)).Tag); switch (i) { case 1: try { excelapp = new Excel.Application(); fExit = true; excelapp.Visible = true; excelapp.SheetsInNewWorkbook = 2; excelappworkbook = excelapp.Workbooks.Add(Type.Missing); excelsheets = excelappworkbook.Worksheets; excelworksheet = (Excel.Worksheet)excelsheets.get_Item(2); excelworksheet.Activate(); sheet_Activate = new Microsoft.Office.Interop.Excel. WorkbookEvents_SheetActivateEventHandler (excelappworkbook_SheetActivate); excelappworkbook.SheetActivate += sheet_Activate; book_SheetChange = new Excel.WorkbookEvents_SheetChangeEventHandler (excelappworkbook_SheetChange); excelappworkbook.SheetChange += book_SheetChange; excelappworkbook.BeforeClose+=new Microsoft.Office. Interop.Excel.WorkbookEvents_BeforeCloseEventHandler (excelappworkbook_BeforeClose); excelappworkbook.BeforeClose += before_bookClose; } catch (Exception ex) { Text = ex.Message; } break; case 2: fExit = false; excelapp.Quit(); break; default: Close(); break; } } public void excelappworkbook_SheetChange(Object Sh, Microsoft.Office.Interop.Excel.Range Target) { MessageBox.Show("Возвращенное значение = " + Target.Value2.ToString()); } public void excelappworkbook_SheetActivate(Object Sh) { MessageBox.Show("Перешли на лист = " + ((Excel.Worksheet)Sh).Name); } public void excelappworkbook_BeforeClose(ref bool Cancel) { // MessageBox.Show("Excel закрывается"); excelappworkbook.BeforeClose -= before_bookClose; excelappworkbook.SheetChange -= book_SheetChange; excelappworkbook.SheetActivate -= sheet_Activate; if(fExit) excelapp.Quit(); fExit = false; } //Для имитатации программной смены листа private void button4_Click(object sender, EventArgs e) { excelworksheet = (Excel.Worksheet)excelsheets.get_Item(1); excelworksheet.Activate(); } } } Отметим, что в функции обработчиков событий Excel передаются не ссылки на конкретный объект типа Workbook, Worksheet, Chart, а переменная типа Object, которую перед использованием необходимо явно привести к требуемому типу. Все события, в имени которых есть слово "Before", позволяют отменить обработку события по умолчанию. Параметр, передаваемый обработчику события, обычно именуется Cancel, а его значение по умолчанию - false. Если присвоить этому параметру True, Excel не выполняет обработку события по умолчанию. Взаимодействие с серверами автоматизации выполняется аналогично выполнению фонового процесса и, поэтому, доступа к элементам, тем, которые представлены контролами или являются свойствами WindowsForm), из функций делегатов нет (хотя при выполнении, например textBox1.Text="Перешли на лист = " + ((Excel.Worksheet)Sh).Name); прерывания не будет, но и отображения информации также не будет). Параграф 11. Об особенности использования метода Activate в VS 2005/2008Кто добросовестно повторял приведенные выше примеры, тот должен был заметить, что при компиляции приложения на строке excelworksheet.Activate(); выдается предупреждение: Ambiguity between method '_Workbook.Activate()' and non-method 'WorkbookEvents_Event.Activate'. Using method group Эта двусмысленность в использовании одноименных свойства и метода объявленных в интерфейсе _Worksheet и интерфейсе DocEvents. Оба эти интерфейса наследует класс Worksheet. И, хотя использование метода Activate не приводит к двусмысленности в выполнении кода, для тех, кто привык писать "чистый код" этот "глюк" лучше устранить. Устранение можно выполнить через события Excel (см. предыдущий параграф). Уберем из предыдущего кода в case 1: две строчки: //excelworksheet = (Excel.Worksheet)excelsheets.get_Item(2); //excelworksheet.Activate(); Вместо убранных строчек напишем вызов: iMySheetActivate(2); Функцию iMySheetActivate запишем следующим образом (как писать код для работы с событиями описано выше): private int iMySheetActivate(int viNumSheet) { try { Excel.Worksheet sheet = (Excel.Worksheet)excelappworkbook.Sheets[viNumSheet]; Excel.DocEvents_Event sheetEvents = (Excel.DocEvents_Event)sheet; Excel._Worksheet _sheet = (Excel._Worksheet)sheet; sheetEvents.Activate += new Excel.DocEvents_ActivateEventHandler(sheetEvents_Activate); _sheet.Activate(); } catch (Exception) { return 1; } return 0; } Делегат может быть и пустым: public void sheetEvents_Activate() { // } Предупреждений компиляции не будет в коде предыдущего параграфа если мы изменим и обработчик нажатия кнопки 4: private void button4_Click(object sender, EventArgs e) { iMySheetActivate(1); } Параграф 12. Автозаполнение или работа с диапазонамиСоздадим файл 1.xls, в который предварительно запишем информацию, показанную на Рис.13.
Рис 13 Файл xls для автозаполнения Выполним следующий код: Excel.Application excelapp; excelapp = new Excel.Application(); excelapp.Visible=true; excelapp.SheetsInNewWorkbook=1; excelapp.Workbooks.Open(@"C:\1.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); Excel.Range vRange=excelapp.get_Range("B1:B2", Type.Missing); Excel.Range vRange1=excelapp.get_Range("B1:B15", Type.Missing); vRange.AutoFill(vRange1,Excel.XlAutoFillType.xlFillSeries); vRange=excelapp.get_Range("C1", Type.Missing); vRange1=excelapp.get_Range("C1:C15", Type.Missing); vRange.AutoFill(vRange1,Excel.XlAutoFillType.xlFillYears); vRange=excelapp.get_Range("D1", Type.Missing); vRange1=excelapp.get_Range("D1:D15", Type.Missing); vRange.AutoFill(vRange1,Excel.XlAutoFillType.xlFillMonths); vRange=excelapp.get_Range("E1", Type.Missing); vRange1=excelapp.get_Range("E1:E15", Type.Missing); vRange.AutoFill(vRange1,Excel.XlAutoFillType.xlFillDefault); vRange=excelapp.get_Range("F1", Type.Missing); vRange1=excelapp.get_Range("F1:F15", Type.Missing); vRange.AutoFill(vRange1,Excel.XlAutoFillType.xlFillWeekdays); vRange=excelapp.get_Range("G1", Type.Missing); vRange1=excelapp.get_Range("G1:G15", Type.Missing); vRange.AutoFill(vRange1,Excel.XlAutoFillType.xlFillDays); vRange=excelapp.get_Range("H1", Type.Missing); vRange1=excelapp.get_Range("H1:H15", Type.Missing); vRange.AutoFill(vRange1,Excel.XlAutoFillType.xlFillDays); ........... Результат выполнения кода показан на Рис.14.
Рис 14. Файл xls после автозаполнения Параграф 13. Некоторые возможности по управлению параметрами ExcelПриведенный ниже код демонстрирует богатство возможностей по управлению параметрами Excel из приложения на C#. Приведенные примеры целесообразно испытывать раздельно (по возможностям) - каждая новая из нескольких приведенных здесь возможностей (их, реально, во много раз больше), начинаются в коде примера фразой "Можно ...". private void button1_Click(object sender, EventArgs e) { int i = Convert.ToInt32(((Button)(sender)).Tag); switch(i) { case 1: //Создадим книги для примеров. Для некоторых примеров нам понадобятся //несколько книг, для других будет достаточно одной. Для приводимых ниже //примеров может понадобиться не только объекты книг, но и объекты //листов и ячеек. Поэтому, здесь кратко напоминается, как это делается. excelapp = new Excel.Application(); excelapp.Visible=true; excelapp.SheetsInNewWorkbook=2; excelapp.Workbooks.Add(Type.Missing); excelapp.SheetsInNewWorkbook=3; excelapp.Workbooks.Add(Type.Missing); excelappworkbooks=excelapp.Workbooks; //Получаем ссылку объект - книга 1 - номерация от 1 excelappworkbook=excelappworkbooks[1]; //Еще будут необходимы объекты Range (ячейки). Но, так как они будут //использоваться не как единый объект, каждый раз перед их //примененим мы будем вновь создавать данный объект. //Можно, используя свойства WindowState задать размер приложения. //Возможные значения: xlNormal, xlMinimized, xlMaximized. excelapp.WindowState=Excel.XlWindowState.xlNormal; //Можно задать полноэкранный режим отображения при значении свойства //DisplayFullScreen равным true и вернуться к обычному режиму: excelapp.DisplayFullScreen=false; //Можно задать размеры при DisplayFullScreen=false; и XlWindowState.xlNormal;, //используя соответствующие значения свойств Width, Height, Left и Top: excelapp.Width=500; excelapp.Height=400; excelapp.Left=10; excelapp.Top=10; //Можно убрать любую из панелей инструментов при значении свойства Visible равным //false для соответствующего CommandBars, который может иметь значения: //Standard, Formatting, Visual Basic, Web, WordArt, Clipboard, External Data, //Exit Design Mode, Stop Recording, Chart, Picture, Reviewing, Drawing, PivotTable //Forms, Control Toolbox. excelapp.CommandBars["Standard"].Visible = true; //Можно получить или изменить форму курсора - свойство Cursor. //Возможные значения: xlDefault, xlIBeam, xlNorthwestArrow, xlWait. //Посмотреть имя курсора: Text=excelapp.Cursor.ToString(); //Изменить курсор: excelapp.Cursor=Excel.XlMousePointer.xlWait; //Можно изменить масштаб отображения документа (свойство Zoom): excelapp.ActiveWindow.Zoom=50; //Можно изменить шрифт по умолчанию и его размер. После рестарта //Excel все выведенное будет отображено данным шрифтом: excelapp.StandardFont="Arial"; excelapp.StandardFontSize=10; //Можно не отображать строку редактирования содержимого ячейки //(свойство DisplayFormulaBar). excelapp.DisplayFormulaBar=false; //Можно запретить редактирование ячеек в самих ячейках (свойство EditDirectlyInCell), //разрешив редактирование только в строке формул. excelapp.EditDirectlyInCell=false; //Можно вообще запретить доступ к документу. Если свойство Interactiv //не вернуть в true, то нельзя будет даже закрыть Excel: xcelapp.Interactive=false; //Можно программно запретить обновление экрана после каждого изменения //и, после выполнения большого объема выводимой информации, разрешить. //Результат - увеличение скорости вывода: excelapp.ScreenUpdating=false; //запретить // .... здесь большой объем выводимой информации excelapp.ScreenUpdating=true; //разрешить //Можно принудительно выполнить пересчеты формул, используя метод Calculate, //в диапазоне ячеек, в книге или во всех открытых рабочих книгах. excelsheets=excelappworkbook.Worksheets; excelworksheet=(Excel.Worksheet)excelsheets.get_Item(1); //Для диапазона: excelcells=excelworksheet.get_Range("A1","С10").Calculate(); //Для книги: excelappworkbook.Calculate(); //Для всех книг: excelapp.Calculate(); //Можно проверить правильность написания текста. Например, //следующие строки дадут результат "Написано некорректно". //В методе CheckSpelling можно задать словарь (второй параметр) //и задать игнорировать ли регистр (третий параметр) при проверки. excelcells=excelworksheet.get_Range("A1",Type.Missing); excelcells.Value2="Текьст"; Text= (excelapp.CheckSpelling(excelcells.Value2.ToString(), Type.Missing, true) ? "Написано корректно" : "Написано некорректно"); //Можно отменить последнее из выполненных действий (метод Undo), выполненное //в самом приложении (не влияет на операции, выполненные из приложения): excelapp.Undo(); //Можно получить и изменить путь сохранения и открытия файлов по умолчанию Text=excelapp.DefaultFilePath; //Выведет Ваш путь excelapp.DefaultFilePath=@"C:\"; Text=excelapp.DefaultFilePath; //Выведет C:\ //Можно создать копию документа, используя метод Workbook NewWindow(). //Например для документа "a" будут созданы окна "a:1" и "a:2": Excel.Window excelwindow=excelappworkbook.NewWindow(); //Можно создать копию документа и по другому - через свойства Application.Workbooks. //Если окон много, то для проверки наличия окна целесообразно //использовать свойство Count. if(excelapp.Windows.Count > 1) { excelwindow=excelapp.Windows[1]; excelwindow.Application.Workbooks[1].NewWindow(); } //Можно изменить расположение окон используя метод Arange. Порядок расположения //определяет первый параметр метода: xlArrangeStyleCascade, xlArrangeStyleHorizontal, //xlArrangeStyleTiled, xlArrangeStyleVertical. Второй параметр при true означает, что //требуется упорядочить только видимые окна активной книги, при false - все. //Третий и четвертый параметр - синхронизация разверток горизонтальной и вертикальной. excelapp.Windows.Arrange(Excel.XlArrangeStyle.xlArrangeStyleVertical, true, true,true); //Можно убрать заголовки строк и столбцов, используя свойство DisplayHeadings: excelwindow.DisplayHeadings = false; //Или так: excelapp.ActiveWindow.DisplayHeadings=false; //Можно при значении свойства DisplayFormulas равным true показываеть в //ячейках формулы (там где они есть), а при false - значения. excelwindow.DisplayFormulas = false; //Можно, используя свойство DisplayWorkbookTabs при true показываеть помимо //Scrollbars позиции табуляции для выбора листов книг и кнопки навигации по //листам, или, убрать их, при значении свойства равным false: excelwindow.DisplayWorkbookTabs = true; //Можно разделить лист путем отделения как, отдельной части, несколько //cтолбцов или строк, используя свойства SplitColumn или SplitRow: excelwindow.SplitColumn = 5; excelwindow.SplitRow = 5; //Можно разделить окно вертикально или горизонтально используя свойства SplitVertical //или SplitHorizontal (практически аналог предыдущего пункта): excelwindow.SplitVertical=10; excelwindow.SplitHorizontal=10; //Можно изменить цвет сетки для листов. //1. Используя свойство GridlineColor: excelwindow.GridlineColor = ColorTranslator.ToOle(Color.Blue); //2. Используя свойство GridlineColorIndex: excelwindow.GridlineColorIndex=(Excel.XlColorIndex)3; //Можно вообще убрать сетку, используя свойство DisplayGridlines: excelwindow.DisplayGridlines=false; //Можно получить список всех недавно открывавшихся файлов. //Для этого используется свойство Eccel.Application - RecentFiles: for (int i = 0; i < excelapp.RecentFiles.Count; i++) { excelcells = (Excel.Range)excelworksheet.Cells[i+1,1]; excelcells.Value2 = excelapp.RecentFiles[i+1].Name; } //Перейти на последнюю заполненную ячейку Excel excelapp.ActiveCell.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing).Select(); breack; Заключение. О богатстве возможностейБогатства возможностей по управлению запущенным приложением потрясающе. Практически, все, что можно сделать в автономно запущенном приложении доступно и из приложения на C#. Каждый может достаточно легко выполнить то или иное действия из приложения, если создаст макрос для этого действия, а, затем, "переведет" код VBA в коды C#. И, в тоже время, по мнению автора, для начального этапа
практической работы по формированию документов из приложения, изложенного
материала вполне достаточно. Но, несмотря на это, раздел будет пополняться по мере возникновения
какой либо проблемы в практической работе и ее разрешении. Если у Вас есть
интересные находки - присылайте - с указанием авторства они будут включены в данный материал.
Молчанов Владислав 1.11.2004г. Адаптировано к VS 2005/2008 14.10.2007г. Перепечатка материала без разрешения автора не допускается. Еcли Вы пришли с поискового сервера - посетите мою главную страничкуНа главной странице Вы найдете программы комплекса Veles - программы для автолюбителей, программы из раздела графика - программы для работы с фото, сделанными цифровым фотоаппаратом, программу Bricks - игрушку для детей и взрослых, программу записную книжку, программу TellMe - говорящий Русско-Английский разговорник - программу для тех, кто собирается погостить за бугром или повысить свои знания в английском, теоретический материал по программированию в среде Borland C++ Builder, C# (Windows приложения и ASP.Net Web сайты).
|