Erweiterte Programmierthemen: Excel-Dokumente lesen und bearbeiten
C# bietet unter anderem eine Schnittstelle zu den Office-Programmen von Microsoft. Ein praktisches Beispiel hierfür ist das Auslesen und die Editierung einer Excel-Tabelle. Die hierfür benötigten Klassen befinden sich im Namensraum Microsoft.Office.Interop.Excel. Zusätzlich ist noch ein Verweis auf „Microsoft Excel xx-Objectlibrary“ nötig, welcher sich in der Gruppe „COM“ befindet.
Die Klasse Application (nicht zu verwechseln mit der Klasse Application des Namensraums System.Windows.Forms) stellt unser Excel-Programm dar und kommuniziert also mit der Excel-Applikation (Excel.exe). Über die Eigenschaft Workbooks können wir auf Arbeitsmappen zugreifen. Mit der Funktion Open() öffnen wir eine Arbeitsmappe. Hierfür übergeben wir der Funktion den Dateinamen (evtl. mit Pfad). Als Rückgabe erhalten wir ein Workbook-Objekt. Dieses stellt eine einzelne Arbeitsmappe bzw. die Datei dar.
Nun müssen wir nur noch auf die einzelnen Tabellen der Arbeitsmappe zugreifen. Die Eigenschaft Worksheets enthält eine Auflistung von allen Tabellen der Arbeitsmappe. Über die Eigenschaft ActiveSheet können wir die aktuelle Tabelle (zumeist die zuletzt bearbeitete Tabelle) abrufen.
Die Klasse Range dient zur Selektion eines Zellbereichs innerhalb unserer Tabelle. Mit Hilfe der Eigenschaft UsedRange des Worksheet-Objekts erhalten wir ein Range-Objekt, welches den vom Benutzer verwendeten Bereich angibt. Die Eigenschaft Rows stellt eine Auflistung (Array) von allen Zeilen zur Verfügung, Columns hingegen die Auflistung aller Spalten. Über die Eigenschaft Cells können wir auf eine einzelne Zelle zugreifen. Hierzu übergeben wir zwei Indexe (da es sich bei der Eigenschaft um ein zwei-dimensionales Array handelt), welche beide 1-basierend sind (nicht 0-basierend). Die Eigenschaft Value gibt den Zellwert zurück. Diese Eigenschaft kann nicht nur gelesen, sondern auch gesetzt werden. Um unser Dokument zu speichern, benötigen wir die Funktion Save() des Workbook-Objekts. Bitte denken Sie am Ende auch daran, die Arbeitsmappe mit Hilfe der Funktion Close() zu schließen.
Im Beispiel verwenden wir eine Windows Forms Applikation mit einem DataGridView-Steuerelement. Mit diesem ist es möglich, Daten tabellarisch darzustellen (also ähnlich wie bei Excel). Das Beispiel-Programm liest die aktuelle Tabelle der gewählten Arbeitsmappe aus. Bei Bedarf können die Zellwerte verändert und die Inhalte über einen Button gespeichert werden.
Form1.cs
using System; using System.Windows.Forms; using Microsoft.Office.Interop.Excel; // zusätzlich ist der Projektverweis auf COM -> Microsoft Excel xx-Objectlibrary namespace CSV20.Excel { public partial class Form1 : Form { // oExcelApp benötigt den kompletten Namensraum, da andernfalls der Compiler den Unterschied zwischen // "Microsoft.Office.Interop.Excel.Application" und "System.Windows.Forms.Application" nicht erkennen kann private Microsoft.Office.Interop.Excel.Application oExcelApp = new Microsoft.Office.Interop.Excel.Application(); private Workbook oWorkbook = null; private Worksheet oWorksheet = null; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { Range oRange; string sSpaltenName; object oValue; if (openFileDialogExcel.ShowDialog() == System.Windows.Forms.DialogResult.OK) { // Datei öffnen und aktives Blatt und benutzten Bereich auswählen oWorkbook = oExcelApp.Workbooks.Open(openFileDialogExcel.FileName); oWorksheet = (Worksheet)oWorkbook.ActiveSheet; oRange = oWorksheet.UsedRange; // Zellen vom Dokument in die Ansicht laden for (int i = 0; i < oRange.Columns.Count; i++) { if (i >= dataGridViewExcel.Columns.Count) { // bilden der Spalten-Namen: A, B, C, D, E, ..., A1, B1, C1, ..., A2, B2, ... sSpaltenName = ((char)('A' + i % 26)).ToString(); if (Math.Floor(i / 26.0) != 0) sSpaltenName += Math.Floor(i / 26.0).ToString(); dataGridViewExcel.Columns.Add(sSpaltenName, sSpaltenName); } for (int j = 0; j < oRange.Rows.Count; j++) { // Zeilen werden nur beim 1. Durchlauf hinzugefügt if (i == 0) dataGridViewExcel.Rows.Add(); oValue = (oRange.Cells[j + 1, i + 1] as Range).Value; // muss unbedingt abgefangen werden if (oValue != null) dataGridViewExcel.Rows[j].Cells[i].Value = oValue.ToString(); } } // Fenster minimieren und danach wieder in normale Fenstergröße zurückkehren, // dies ist ein Trick, sodass wir die Anwendung wieder in den Vordergrund bekommen, // da Excel unsichtbar geöffnet wird this.WindowState = FormWindowState.Minimized; this.WindowState = FormWindowState.Normal; } else // Bei Abbruch, Fenster schließen Close(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { // Beim Schließen des Fensters, Dokument schließen if (oWorkbook != null) oWorkbook.Close(); } private void buttonSpeichern_Click(object sender, EventArgs e) { if (MessageBox.Show("Sind Sie sicher dass Sie die Änderungen übernehmen möchten?\nDie Quelldatei wird überschrieben!", "Speichern?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { // Daten von der Ansicht in das Dokument schreiben for (int i = 0; i < dataGridViewExcel.Rows.Count - 1; i++) for (int j = 0; j < dataGridViewExcel.Columns.Count; j++) if (dataGridViewExcel.Rows[i].Cells[j].Value != null) (oWorksheet.Cells[i + 1, j + 1] as Range).Value = dataGridViewExcel.Rows[i].Cells[j].Value.ToString(); else (oWorksheet.Cells[i + 1, j + 1] as Range).Value = ""; // Speichervorgang auslösen oWorkbook.Save(); } } } }